2011-02-01 5 views
3

Q: все должности и связанные с ними комментарии выбор в одном запросе, загрузка комментариев отношение к p.comments, но выбрать только название из комментариеврельсы Активная запись выбора

Сообщение

#db 
create_table :posts do |t| 
    t.string :title 
    t.text :text 

    t.timestamps 
end 

#modlel 
class Post < ActiveRecord::Base 
    has_many :comments 
end 

Комментарий

#db 
create_table :comments do |t| 
    t.string :title 
    t.text :text 
    t.integer :post_id 

    t.timestamps 
end 

#model 
class Comment < ActiveRecord::Base 
    belongs_to :post 
end 

Что мне нужно: Отметить все комментарии и комментарии к ним в одном запросе и загрузить отношения комментариев в p.comments, но выберите только заголовок из комментариев:

posts = Post.includes(:comments).select("posts.*, comments.title") 
posts.each do |p| 
    puts(p.title) 
    puts(p.text) 
    p.comments.each do |c| 
     puts(c.title) 
    end 
end 

Если первая часть сделана .includes:

posts = Post.includes(:comments).select('posts.*, comments.title') 
posts.first.comments.loaded? # true 

=> SELECT posts. id AS t0_r0, posts. title AS t0_r1, posts. text AS t0_r2, posts. created_at AS t0_r3, posts. updated_at AS t0_r4, comments. id AS t1_r0, comments. title AS t1_r1, comments. text AS t1_r2, comments. post_id AS t1_r3, comments. created_at AS t1_r4, comments. updated_at AS t1_r5 FROM posts LEFT OUTER JOIN comments ON comments. post_id = posts. id

его полностью игнорирует выбор.

Хорошо, давайте попробуем присоединяется:

Post.joins(:comments).select('posts.*, comments.title') 

=> SELECT сообщения * comments.title FROM posts INNER JOIN comments НА comments.. post_id = posts. id

лучше, но нам нужно таблица псевдоним - Rails не обрабатывает отношения

posts = Post.joins(:comments).select('posts.*, comments.title as comments_title').first 

=> SELECT сообщения * comments.title в comments_title ОТ posts INNER JOIN comments НА comments (почему?). , post_id = posts. id

posts.first.comments.loaded? # false 
posts.first.comments_title # "Comment 1.1" 

Хорошо, давайте попробуем AREL

p = Post.arel_table 
c = Comment.arel_table 
posts = Post.find_by_sql(
    p.join(c).on(c[:post_id].eq(p[:id])) \ 
    .project(p[:id],p[:title],c[:id],c[:title]).to_sql 
) 

=> SELECT posts. id, posts. title, comments. id, comments. title ОТ posts INNER JOIN comments ON comments. post_id = posts.id

та же история - ActiveRecord не обрабатывает отношение.

любые предложения?

UPD

  1. , если этот вопрос не имеет прямого решения, может быть, есть способ использовать некоторые методы AR для преобразования в результате запроса. Потому что AR использует AREL, затем называет find_by_sql, а затем делает некоторую магию, которую я не могу найти, когда и когда она была выполнена, и альт: сгенерированные псевдонимы и ассоциации загрузки.

  2. Возможно, существует решение для отношения «один-к-одному»?

    Должности = Post.select ('posts.id, posts.title, comments.id, comments.title'). Включает (: комментарий) posts.first.comment.loaded? #true

=> SELECT posts. id AS t0_r0, posts. title AS t0_r1, posts. text AS t0_r2, posts. created_at AS t0_r3, posts. updated_at AS t0_r4, comments. id AS t1_r0, comments. title AS t1_r1, comments. text AS t1_r2, comments. post_id AS t1_r3, comments. created_at AS t1_r4, comments. updated_at AS t1_r5 FROM posts LEFT OUTER JOIN comments ON comments. post_id = posts. id

ответ

3

Боюсь, у меня нет никаких предложений, потому что все описанные вами сценарии работают по назначению.

  • : включает в себя => жадная загрузка
  • : присоединяется => НЕ жадная загрузка

Так что, если вы хотите, комментарии должны быть загружены непосредственно вы должны использовать включает в себя, присоединяется никогда не будет работать.

Следующее, что требует загрузки, связано с определенным синтаксисом выбора, используемым в SQL-запросе. Другими словами, ваш указанный select будет проигнорирован при использовании в сочетании с include и все столбцы будут загружены по умолчанию.

Я думаю, что самая последняя попытка добавить функциональность, которую вы ищете, описана in this ticket, где она разрешена добавлением параметра except в входящий вызов. Тем не менее, похоже, он не получил ответа.

Лично я бы пошел на первый пример, который вы указали с помощью include, но пропустите выделение и живите с тем, что загружен comment.text. Лучше тогда любой другой сценарий, о котором я могу думать.

+0

tnx для связи. Если я не найду какое-либо решение, это будет полезно – AlexParamonov

0

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

post_comment = Post.find_by_sql("SELECT p.*, c.title AS comment_title FROM posts p JOIN comments c ON p.id=c.post_id").first 
post_comment.comment_title 

Немного Hacky, но это, кажется, работает. ActiveRecord также предоставляет атрибут соединения для выполнения еще более сложных запросов. http://apidock.com/rails/ActiveRecord/Base/connection

+0

. Дело было в создании объекта и загрузке только заголовка. – AlexParamonov

+0

вы имеете в виду, что вы все еще хотели создать класс Comment, но вместо этого вместо него должен быть только заголовок с его полным набором атрибутов? –

+0

Да, это вызывает ленивую загрузку – AlexParamonov