2012-07-17 62 views
0

我有一個應用程序,用戶可以在其中定製日曆並使用給定的事件池填充日曆。用戶也可以用別名覆蓋他自己日曆的標題。所以我有以下has_many:通過關係:Rails:如何在has_many:through關係中使用JOIN設置IF條件

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 

但是,這一個會導致太多的查詢給我。

那麼有什麼更聰明的方式來完成我想要的?也許使用命名範圍或其他花式導軌技術?

UPDATE

我結束了做一個 「自定義」 通過的has_many選擇:通過關係。所以,唯一的變化是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 /的title現在情況有點像@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 

回答

1

如何使用includes在拉別名的同時抓取事件。

Calendar.find(1).event_aliases.includes(:event).each do |e| 
    puts e.custom_name.blank? ? e.event.title : e.custom_name 
end 

的SQL Rails的產生會是這個樣子:

Calendar Load (0.2ms) SELECT "calendars".* FROM "calendars" WHERE "calendars"."id" = ?  LIMIT 1 
EventAlias Load (0.2ms) SELECT "event_aliases".* FROM "event_aliases" WHERE "event_aliases"."calendar_id" = 1 
Event Load (0.2ms) SELECT "events".* FROM "events" WHERE "events"."id" IN (1, 2) 

如果你想去把它清理乾淨一點,你可以將虛擬字段添加到EventAlias

class EventAlias < ActiveRecord::Base 

    def name 
    custom_name || self.event.title 
    end 

end 

只要你使用包含,查詢將是相同的。

+0

感謝您的提示。那麼'include()'解決方案與'joins()'解決方案沒有多大區別。在你的解決方案中,你只需在Ruby中而不是SQL中創建if條件。我想出了另一個受此影響的解決方案,但需要少一個查詢。 – LeEnno 2012-07-18 06:52:55

相關問題