Обновление: это может быть что-то, что просто невозможно сделать. Смотрите это
TLDR: Как вы условно загружаете ассоциацию (скажем, загружаете ассоциацию только для текущего пользователя), в то же время включая записи, которые вообще не имеют этой ассоциации?
Rails 3.1, вот примерно модель, с которой я работаю.
class User
has_many :subscriptions
has_many :collections, :through => :subscriptions
end
class Collection
has_many :things
end
class Thing
has_many :user_thing_states, :dependent => :destroy
belongs_to :collection
end
class Subscription
belongs_to :user
belongs_to :collection
end
class UserThingState
belongs_to :user
belongs_to :thing
end
Существует много коллекций, в которых есть много вещей. Пользователи подписываются на множество коллекций и тем самым подписываются на многие вещи. Пользователи имеют состояние по отношению к вещам, но не обязательно, и все еще подписаны на вещи, даже если у них нет состояния для них. Когда пользователь подписывается на коллекцию и связанные с ней вещи, состояние не генерируется для каждой отдельной вещи (которая может быть сотнями). Вместо этого состояния генерируются, когда пользователь впервые взаимодействует с данной вещью. Теперь проблема: я хочу выбрать все подписанные пользователем вещи при загрузке состояния пользователя для каждой вещи, где оно существует.
Концептуально это не так сложно. Для справки, SQL, который должен получить мне данные, необходимые для этого:
SELECT things.*, user_thing_states.* FROM things
# Next line gets me all things subscribed to
INNER JOIN subscriptions as subs ON things.collection_id = subs.collection_id AND subs.user_id = :user_id
# Next line pulls in the state data for the user
LEFT JOIN user_thing_states as uts ON things.id = uts.thing_id AND uqs.user_id = :user_id
Я просто не знаю, как собрать это вместе в рельсы. Что происходит в классе Thing? Thing.include (: user_thing_states) будет загружать все состояния для всех пользователей, и это выглядит как единственный инструмент. Мне нужно что-то вроде этого, но я не уверен, как (или если это возможно):
class Thing
has_many :user_thing_states
delegates :some_state_property, :to => :state, :allow_nil => true
def state
# There should be only one user_thing_state if the include is correct, state method to access it.
self.user_thing_states.first
end
end
Мне нужно что-то вроде:
Thing.includes(:user_question_states, **where 'user_question_state.user_id => :user_id**).by_collections(user.collections)
Тогда я могу сделать
things = User.things_subscribed_to
things.first.some_state_property # the property of the state loaded for the current user.