我有一个应用程序,用户可以在其中自定义日历并用给定的事件池填充它。用户还可以用别名覆盖他自己的日历的标题。所以我有以下 has_many :through 关系:
class Calendar < ActiveRecord::Base
has_many :event_aliases
has_many :events, :through => :event_aliases
end
class Event < ActiveRecord::Base
attr_accessible :title
has_many :event_aliases
has_many :calendars, :through => :event_aliases
end
class EventAliases < ActiveRecord::Base
attr_accessible :course_id, :calendar_id, :custom_name
belongs_to :event
belongs_to :calendar
end
不,我想提供带有别名的日历。如果事件有别名 ( custom_name
),则应该显示它。title
否则应显示默认事件名称 ( )。
有没有一种方法可以轻松设置一个查询,该查询返回当前日历的所有事件,无论是custom_name
(如果存在)还是使用默认值title
?
我当前的解决方案是将 if 条件硬编码到我想避免的查询中。
title_column = "case when custom_name IS NOT NULL then custom_name else title end as title"
# assume we are given a calendar_id
Calendar.find(calendar_id).event_aliases.joins(:event).select(title_column, :event_id).each do |event_alias|
# do further stuff here
end
如果需要,我还可以获取所有event_aliases
并遍历它们中的每一个以获取默认值title
。
# assume we are given a calendar_id
Calendar.find(calendar_id).event_aliases.each do |event_alias|
title = event_alias.custom_name
if title.nil?
title = Event.find(event_alias.event_id).title
# do further stuff here
end
但这给我带来了太多的查询。
那么有没有更聪明的方法来完成我想要的?也许使用命名范围或其他花哨的导轨技术?
更新
我最终通过 has_many :through 关系进行了“自定义”选择。所以唯一改变的是Calendar
模型:
class Calendar < ActiveRecord::Base
has_many :event_aliases
has_many :events, :through => :event_aliases,
:select => "event_aliases.custom_name as custom_name, events.*"
end
所以访问custom_name
/ the title
now 有点像@Doon 建议的那样:
Calendar.find(1).courses.each do |course|
title = course.custom_name || course.title
end
这只会创建 2 个查询而不是 3 个:
Calendar Load (0.6ms) SELECT `calendars`.* FROM `calendars` WHERE `calendars`.`id` = 1 LIMIT 1
Event Load (0.7ms) SELECT event_aliases.custom_name as custom_name, events.* FROM `events` INNER JOIN `event_aliases` ON `events`.`id` = `event_aliases`.`event_id` WHERE `event_aliases`.`calendar_id` = 1