Как вы оцениваете Ассоциации ActiveRecord в Rails 3?
у меня есть проект Rails 3. С Rails 3 появилась Arel и возможность повторного использования одной области для создания другой. Мне интересно, есть ли способ использовать области при определении отношения (например, "has_many").
у меня есть записи, которые имеют столбцы разрешения. Я хотел бы построить default_scope, который учитывает мои столбцы разрешений, чтобы фильтровать записи (даже те, к которым обращаются через отношения).
В настоящее время, в Rails 3, default_scope (включая патчи, которые я нашел) не предоставляют работоспособных средств передачи proc (которые мне нужны для позднего привязки переменных). Можно ли определить has_many, в который может быть передана именованная область?
идея повторного использования именованной области будет выглядеть так:
Orders.scope :my_orders, lambda{where(:user_id => User.current_user.id)}
has_many :orders, :scope => Orders.my_orders
или неявное кодирование, что именованная область в отношениях будет выглядеть так:
has_many :orders, :scope => lambda{where(:user_id => User.current_user.id)}
Я просто пытаюсь применить default_scope с поздним связыванием. Я бы предпочел использовать подход Arel (если есть один), но будет использовать любой работоспособный вариант.
поскольку я имею в виду текущего пользователя, я не могу полагаться на условия, которые не оцениваются в самый последний момент, например:
has_many :orders, :conditions => ["user_id = ?", User.current_user.id]
6 ответов:
Я предлагаю вам взглянуть на "именованные области мертвы"
автор объясняет там, насколько мощный Arel:)
Я надеюсь, что это поможет.
редактировать #1 марта 2014
Как утверждают некоторые комментарии, разница теперь является вопросом личного вкуса.
тем не менее, я по-прежнему лично рекомендую не подвергать область Arel верхнему уровню (будучи контроллером или чем-либо еще, что напрямую обращается к моделям), и делать это потребуется:
- создайте область и предоставьте ее через метод в вашей модели. Этот метод будет тот, который вы предоставляете контроллеру;
- если вы никогда не подвергаете свои модели вашим контроллерам (так что у вас есть какой-то уровень обслуживания поверх них), то вы в порядке. Антикоррупционный слой и ваш сервис и он может получить доступ к области вашей модели, не слишком беспокоясь о том, как реализуются области.
Как насчет расширения ассоциации?
class Item < ActiveRecord::Base has_many :orders do def for_user(user_id) where(user_id: user_id) end end end Item.first.orders.for_user(current_user)
UPDATE: я хотел бы указать на преимущество расширений ассоциации в отличие от методов класса или областей заключается в том, что у вас есть доступ к внутренним компонентам прокси-сервера ассоциации:
proxy_association.владелец возвращает объект, частью которого является Ассоциация. proxy_association.отражение возвращает объект отражения, описывающий ассоциацию. proxy_association.target возвращает связанный объект для belongs_to или has_one, или коллекция связанных объектов для has_many или has_and_belongs_to_many.
подробнее здесь: http://guides.rubyonrails.org/association_basics.html#association-extensions
вместо областей я только что определял class-методы, которые отлично работают
def self.age0 do where("blah") end
Я использую что-то вроде:
class Invoice < ActiveRecord::Base scope :aged_0, lambda{ where("created_at IS NULL OR created_at < ?", Date.today + 30.days).joins(:owner) } end
можно использовать слияние метод для объединения областей из разных моделей. Для получения более подробной информации поиск слияния в этом railscast
Если вы просто пытаетесь получить заказы пользователя, почему бы тебе просто не использовать отношения?
предполагая, что текущий пользователь доступен из метода current_user в контроллере:
@my_orders = current_user.orders
Это гарантирует, что будут показаны только конкретные заказы пользователя. Вы также можете сделать произвольно вложенные соединения, чтобы получить более глубокие ресурсы с помощью
joins
current_user.orders.joins(:level1 => { :level2 => :level3 }).where('level3s.id' => X)