0

ユーザーがカレンダーをカスタマイズして、特定のイベントのプールを入力できるアプリケーションがあります。ユーザーは自分のカレンダーのタイトルを別名で上書きすることもできます。したがって、次の 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/へのアクセスは、 title@Doon が提案したように少し行われるようになりました。

Calendar.find(1).courses.each do |course|
    title = course.custom_name || course.title
end

これにより、3 つではなく 2 つのクエリのみが作成されます。

  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
4

1 に答える 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

インクルードを使用する限り、クエリは同じになります。

于 2012-07-17T12:52:06.410 に答える