установщик rails has_many должен устанавливать условия, если указано

#ruby-on-rails #ruby-on-rails-3 #activerecord #associations

#ruby-on-rails #ruby-on-rails-3 #activerecord #ассоциации

Вопрос:

Мне это кажется ошибкой в Rails, но, вероятно, я мало что могу с этим поделать. Итак, как я могу выполнить ожидаемое поведение?

Предположим, у нас есть:

 class User < ActiveRecord::Base
  has_many :awesome_friends, :class_name => "Friend", :conditions => {:awesome => true}
end
  

И выполнить код:

 >> my_user.awesome_friends << Friend.new(:name=>'jim')
  

Впоследствии, когда я проверяю этот объект friend, я вижу, что поле user_id заполнено. Но я бы также ожидал увидеть, что для столбца «awesome» установлено значение «true», которым оно не является.

Кроме того, если я выполню следующее с консоли:

 >> my_user.awesome_friends << Friend.new(:name=>'jim')
>> my_user.awesome_friends
= [#<Friend id:1, name:"jim", awesome:nil>]
# Quit and restart the console
>> my_user.awesome_friends
= []
  

Есть мысли по этому поводу? Я полагаю, что хэш условий может быть произвольно сложным, что делает невозможной интеграцию в установщик. Но в некотором смысле кажется, что по умолчанию мы передаем условие «:user_id => self.id «, и это устанавливается, так что не должны ли другие?

Спасибо, Майк

Редактировать:

Я обнаружил, что для has_many существуют обратные вызовы, поэтому я думаю, что мог бы определить взаимосвязь следующим образом:

 has_many :awesome_friends,
         :class_name => "Friend",
         :conditions => {:awesome => true},
         :before_add => Proc.new{|p,c| c.awesome = true},
         :before_remove => Proc.new{|p,c| c.awesome = false}
  

Хотя, начинает казаться, что, возможно, я просто реализую какой-то другой, существующий шаблон проектирования. Может быть, мне следует создать подкласс AwesomeFriend < Друг? В конечном счете, мне нужна пара таких отношений has_many, а при создании подкласса get все дополнительные файлы запутаны..

РЕДАКТИРОВАТЬ 2:

Хорошо, спасибо всем, кто прокомментировал! В конечном итоге я превратил описанный выше метод в приятное маленькое расширение ActiveRecord ‘has_many_of_type’. Который работает следующим образом:

 has_many_of_type :awesome_friends, :class_name => "Friend", :type=>:awesome
  

Который просто преобразуется в has_many с соответствующими условиями, параметрами before_add и before_remove (и это предполагает существование столбца с именем friend_type).

Ответ №1:

Вам нужно использовать:

my_user.awesome_friends.create(:name=>'jim') или my_user.awesome_friends.build(:name=>'jim')

В документации: has_many (:conditions)

Область создания записей из ассоциации ограничена, если используется хэш. has_many :posts, :conditions => {:published => true} создаст опубликованные сообщения с помощью @blog.posts.create или @blog.posts.build.

Комментарии:

1. Приятно! Я забыл об этом. Хотя это не решает проблему добавления / удаления существующего друга. Хотя, спасибо, я, вероятно, использую это для своей реализации.

2. Да. Я не думаю, что он когда-либо изменит существующий объект при добавлении его в коллекцию, кроме как для установки внешнего ключа.

3. Принял это, потому что это было лучшее решение проблемы, которую я поставил. Однако окончательную реализацию смотрите в изменениях в вопросе.

4. Я бы создал методы add_to_awesome_friends и remove_from_awesome_friends и внедрил в него логику с использованием существующего объекта «Friend».

Ответ №2:

Во-первых, это :class_name скорее, чем :class .

Ответ №3:

Я не думаю, что это ошибка. Хэш :conditions определяет только то, как вы запрашиваете объекты. Но я не думаю, что рационально просто предполагать, что любой объект, который вы помещаете в коллекцию, может быть создан в соответствии с условиями.

В вашем простом примере это имеет смысл, но вы также могли бы добавить туда более сложную логику.

Документация также кажется довольно ясной по этому поводу:

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

:conditions

Укажите условия, которым должен соответствовать связанный объект, чтобы быть включенным в качестве WHERE фрагмента SQL, например authorized = 1 .

Комментарии:

1. Я согласен, документация довольно ясна, это было первое, что я проверил. Но на практике это действительно не имеет смысла для меня. Я думаю, мне просто нужно быть осторожным, чтобы установить соответствующие поля в моем объекте «Friend» перед добавлением в коллекцию.

2. В этом случае я бы предпочел создать метод add_friend, который выполняет логику за вас.