

`Post`

  * id
  * title
  * body

`Comment`

  * id
  * body
  * post_id

この2つをリレーションで組んだ時、データを取得する際のカラムの指定の仕方がわかりません。

たとえば、`Post.id`,`Post.title`,`Comment.id`,`Comment.body`を取得したい場合はどのように`select()`を書けば良いのでしょうか?


CC BY-SA 3.0
2015-01-01T12:52:38.127
2907
2015-02-17T11:07:34.437
2015-01-15T14:57:41.800
4978
5855
question
ruby rails-activerecord
ActiveRecordでリレーションを組んだカラムの指定方法


すでにリレーションをくんだ前提(has_many, belongs_toアソシエーションの記載済み)で話をします。
リレーションに関しては説明がドットインストールにもありますので参考にしてみてください。
(<http://dotinstall.com/lessons/basic_rails_v2>)

その場合なら、例えばidが１のポストに対するのコメントをとりたいのであれば、

[code]

    @post = Post.where(id = 1)
    @post.id //ここにpostのIDが入っています。
    @post.title //ここにpostのIDが入っています。
    @post.Comment.id //ここにコメントのIDが入っています。
    @post.Comment.body //ここにコメントのbodyが入っています。
    
[/code]

のようにすれば、必要なものが取得できるかと思います。


CC BY-SA 3.0
2015-01-01T17:27:53.943
2922
2015-01-01T17:27:53.943
5330
2907
answer


PostクラスとCommentクラスがこんなふうに定義されてるとします。

[code]

    class Post
      has_many :comments
    end
    
    class Comment
      belongs_to :post
    end
    
[/code]

特定のPost1件と、それにひもづくCommentの一覧を表示する場合はこんなふうになります。

[code]

    class PostController < ApplicationController
      def show
        @post = Post.find(params[:id])
      end
    end
    
[/code]

こちらはViewです。(`views/posts/show.html.erb`)

[code]

    Title: <%= @post.title %>
    Body: <%= @post.body %>
    Comments:
    <ul>
    <% @post.comments.each do |comment| %>
    <li><%= comment.body %></li>
    <% end %>
    </ul>
    
[/code]

複数のPostと、それぞれのPostに紐付くCommentの一覧を取得するのであれば、このようになるはずです。

[code]

    posts = Post.all # または Post.where(title: '今日のできごと') など
    posts.each do |post|
      id = post.id
      title = post.title
      body = post.body
      post.comments.each do |comment|
        comment_id = comment.id
        comment_body = comment.body
        post_id = comment.post_id
      end
    end
    
[/code]

ちなみに、関連を持つモデルのデータの作成方法は昔Qiitaで詳しく説明したので、そちらも良かったら参考にしてみてください。

[[初心者向け]
Railsで関連するデータ(親子関係)を保存する方法あれこれ](http://qiita.com/jnchito/items/7f41ff3df900909952db)


CC BY-SA 3.0
2015-01-01T18:42:44.457
2923
2015-01-01T18:42:44.457
85
2907
answer


以下の様なことでしょうか？

[code]

    @posts = Post.joins(:comments)
                 .select('posts.id, comments.id as cid, posts.body, comments.body as cbody')
    
[/code]

これのto_sql は以下になります(改行は私が入れました)。

[code]

    SELECT posts.id, comments.id as cid, posts.body, comments.body as cbody 
      FROM "posts" INNER JOIN 
           "comments" ON "comments"."post_id" = "posts"."id"
    
[/code]

モデルは以下のようになっています。

[code]

    class Post < ActiveRecord::Base
      has_many :comments
    end
    
    class Comment < ActiveRecord::Base
      belongs_to :post
    end
    
[/code]


CC BY-SA 3.0
2015-01-02T04:59:59.407
2934
2015-01-02T04:59:59.407
728
2907
answer


「参照の仕方ではなく取得の仕方です」ということですから。  
おそらくSELECT文の時点で絞り込みたいのだと思います。

しかし「Post.id,Post.title,Comment.id,Comment.body」の4つを取得した時に、  
取得したインスタンスに対しての .id が Post.idを示すのかComment.idを示すのか判断できません。

一般的には、flied onionさんのように、select('posts.id as ...')としますが。  
arel_tableを使うと自由度は高まります。

[code]

    p1 = Post.arel_table['id']
    p2 = Post.arel_table['title']
    c1 = Comment.arel_table['id'].as('comment_id')
    c2 = Comment.arel_table['body']
    posts = Post.joins(:comment).select(p1, p2, c1, c2)
    posts.first.body # 行データに収まっているのでincludes不要
    
[/code]

もちろん Post.arel_table['*']もOKです。

私自身arel_tableを頻繁に使わないので希望に添えているかどうかとか。  
もっと綺麗な使い方があるんじゃないかとか多少心配がありますが。  
テーブル名を文字列で渡して、ピリオドやクォートが手間だと思い始めたら  
arel_tableを使うことを検討してください。

※ activerecord-sqlserver-adapterの環境下で問題ないことは確認しました。


CC BY-SA 3.0
2015-02-17T11:07:34.437
6641
2015-02-17T11:07:34.437
8335
2907
answer