Rails скалярный запрос - PullRequest
       7

Rails скалярный запрос

1 голос
/ 29 апреля 2010

Мне нужно отобразить элемент пользовательского интерфейса (например, звездочку или галочку) для сотрудников, которые являются «избранными» текущего пользователя (другого сотрудника).

Для модели Employee определены следующие отношения:

  has_and_belongs_to_many :favorites, :class_name => "Employee", :join_table => "favorites",
    :association_foreign_key => "favorite_id", :foreign_key => "employee_id"

Избранное имеет два поля: employee_id, favour_id.

Если бы я написал SQL, следующий запрос дал бы мне желаемые результаты:

SELECT  id, account, 
    IF(
    (
    SELECT  favorite_id
    FROM    favorites
    WHERE   favorite_id=p.id
    AND employee_id = ?
    ) IS NULL, FALSE, TRUE) isFavorite
FROM        employees

Где '?' будет заменен сеансом [: user_id].

Как мне представить скалярный запрос isFavorite в Rails?

Другой подход будет использовать такой запрос:

SELECT  id, account, IF(favorite_id IS NULL, FALSE, TRUE) isFavorite
FROM        employees e
LEFT OUTER JOIN favorites f ON e.id=f.favorite_id
    AND employee_id = ?

Опять "?" заменяется значением session [: user_id].

У меня был некоторый успех в написании этого на Rails:

ee=Employee.find(:all, :joins=>"LEFT OUTER JOIN favorites ON employees.id=favorites.favorite_id AND favorites.employee_id=1", :select=>"employees.*,favorites.favorite_id")

К сожалению, когда я пытаюсь сделать этот запрос «динамическим», заменив «1» на «?», Я получаю ошибки.

ee=Employee.find(:all, :joins=>["LEFT OUTER JOIN favorites ON employees.id=favorites.favorite_id AND favorites.employee_id=?",1], :select=>"employees.*,favorites.favorite_id")

Очевидно, у меня неправильный синтаксис, но могут ли выражения объединений быть «динамическими»? Это случай для лямбда-выражения?

Я надеюсь добавить другие фильтры к этому запросу и использовать его с will_paginate и acts_as_taggable_on, если это имеет значение.

редактировать

ошибки при попытке сделать :joins динамическим:

ActiveRecord::ConfigurationError: Association named 'LEFT OUTER JOIN favorites ON employees.id=favorites.favorite_id AND favorites.employee_id=?' was not found; perhaps you misspelled it?
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1906:in `build'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1911:in `build'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1910:in `each'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1910:in `build'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1830:in `initialize'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1789:in `new'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1789:in `add_joins!'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1686:in `construct_finder_sql'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1548:in `find_every'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:615:in `find'

Ответы [ 3 ]

3 голосов
/ 29 апреля 2010

Попробуйте это:

ee=Employee.all( 
  :select=>"employees.*,favorites.favorite_id",
  :joins=>"LEFT OUTER JOIN favorites AS favorites 
           ON employees.id=favorites.favorite_id AND
              favorites.employee_id = #{session[:user_id]}")

Или, если быть точным:

joins = Employee.send(:sanitize_sql_array, 
             ["LEFT OUTER JOIN favorites AS favorites 
               ON employees.id=favorites.favorite_id AND
                  favorites.employee_id = ? ", session[:user_id]
             ])

ee=Employee.find(:all, 
  :select=>"employees.*,favorites.favorite_id",
  :joins=> joins )

Второй подход решает проблемы внедрения SQL.

Редактировать 1

Чтобы проверить эти вызовы в irb, сделайте следующее:

Имитировать объект сеанса, создавая хэш:

>> session = {:user_id => "1" }
session = {:user_id => "1" }
=> {:user_id=>"1"}

Выполнить поиск:

>> ee=Employee.find(:all, 
      :select=>"employees.*,favorites.favorite_id",
      :joins=>"LEFT OUTER JOIN favorites AS favorites 
               ON employees.id=favorites.favorite_id AND
                  favorites.employee_id = #{session[:user_id]}")
0 голосов
/ 29 апреля 2010

:joins ожидает либо необработанную строку, либо символ (имя ассоциации), либо массив ассоциаций. Таким образом, вы не можете иметь динамические условия там.

См. Раздел параметров здесь .

0 голосов
/ 29 апреля 2010

Я думаю, что возможны оба способа, но обычно я бы вставил условие в предложение WHERE (:conditions):

ee = Employee.find(:all,
    :select => 'employees.*, favorites.favorite_id',
    :conditions => ['favorites.employee_id = ?', 1],
    :joins => 'LEFT OUTER JOIN favorites ON employees.id = favorites.favorite_id'
)
...