Почему ассоциация модели Rails не является естественной? ActiveRecord :: Relations?

Я использую Rails 3.2.0

Скажем, у меня есть:

class Comment < ActiveRecord::Base
  has_many :articles
end

c1 = Comment.last

тогда

c1.articles.class
# => Array

c1.articles.where('id NOT IN (999999)').class
# => ActiveRecord::Relation    

Почему результат ассоциации не тип ActiveRecord :: Relation ?

Очевидно, что она была/была в какой-то момент :

c1.articles.to_orig
# undefined method `to_orig' for #

c1.articles.class
# => Array

Некоторые оценки действуют на объект ActiveRecord :: Relation, но проверка класса дает другой тип.


В частности, это разрушает создание ленивых запросов при использовании merge для concat нескольких запросов.

12
nl ja de
Если я правильно помню, метод класса лжет вам - он делегирует цель, которая является массивом
добавлено автор Frederick Cheung, источник
Какая версия Rails?
добавлено автор Andrew Marshall, источник
@AndrewMarshall 3.2.0
добавлено автор New Alexandria, источник

2 ответы

Это ActiveRecord :: Relation , но Rails намеренно лежит на вас . Вы можете видеть это уже в вызовах метода и продолжать видеть его, вызывая ancestors , который включает в себя множество классов ActiveRecord:

c1.articles.ancestors.select { |c| c.to_s =~ /ActiveRecord/ }.size  #=> 35

который показывает, что это очень много not Array .

Это происходит потому, что то, что вы возвращаете при вызове c1.articles , является ActiveRecord :: Ассоциации :: CollectionProxy *, который undefines class (наряду со многими другими способами). Это означает, что class получает делегирование через его method_missing , который отправляет его в target . Как мы видим, класс target здесь, по сути, Array :

c1.articles.target.class  #=> Array

Вот откуда приходит c1.articles.class . Тем не менее, ActiveRecord :: Relation .

<Суб> * Мы можем проверить, что это действительно ActiveRecord :: Associations :: CollectionProxy , вызывая метод оригинального класса ruby для объекта, о котором идет речь: Object. instance_method (: класс) .bind (c1.articles) .call . Это хороший трюк, чтобы убедиться, что объект не пытается притвориться другим классом.

15
добавлено
@AndrewMarshall - я хотел бы рассказать вам об этой ситуации: stackoverflow.com/questions/16927437/…
добавлено автор Nathan Long, источник
Аккуратный трюк, не думал об этом раньше
добавлено автор Frederick Cheung, источник
этот ответ должен иметь гораздо больше оборотов, чем он.
добавлено автор sevenseacat, источник
Поиск этого вопроса/ответа восстановил мое здравомыслие после битвы с CollectionProxy в одежде Array всю неделю. :)
добавлено автор woodardj, источник

Потому что, когда вы определяете ассоциацию, она помещается в вашу модель:

def #{name}(*args)
  association(:#{name}).reader(*args)
end

.reader() returns AssociationProxy, which removes the .class method and delegates unknown methods to @target through .method_missing.

2
добавлено
pro.ruby
pro.ruby
1 181 участник(ов)

Язык программирования Ruby Additional docs: https://rubyreferences.github.io/rubyref/ Invite: https://telegram.me/joinchat/Be4rsT2NuB3CyJaF26j1kA Кто хочет компилировать: @crystal_ru (его синтаксис основан на Ruby) Участник @proDOT

Ruby, Rails, Hanami | dry-rb
Ruby, Rails, Hanami | dry-rb
1 180 участник(ов)

https://telegram.me/rubyjob - Ruby Job По вопросам - @eugene_shved

Ruby School .us
Ruby School .us
1 045 участник(ов)

Чат-болталка для учеников руби-школы и не только. Правила: https://telegra.ph/Pravila-chata-Rubi-shkoly-03-13

Random Ruby Chat
Random Ruby Chat
589 участник(ов)

Правила публикации вакансий: https://t.me/codenamecrud/60865

Rubyata
Rubyata
333 участник(ов)

Коммюнити Ruby и Ruby On Rails Флуд не приветствуются. Вакансии можно публиковать только и ТОЛЬКО по пятницам с хештегом #вакансия.

Ruby Talks
Ruby Talks
236 участник(ов)

Национальная Флеймотека

RubyRush
RubyRush
189 участник(ов)

rubyrush.ru программирование для самых новичков

Rails Chat
Rails Chat
87 участник(ов)

You are welcome to discuss Ruby On Rails development process and other stuff