質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.35%

【Rails】多対多の関係において、親モデルのデータ取得が出来ないです。お気に入り機能実装で躓いています。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 4,127

score 80

Shop_basicモデルと1対1関係にあるShopモデルが投稿したPostモデルを、Userモデルはお気に入りに登録できる、という機能を実装しています。

そこで、実際にお気に入りに登録する機能自体は実装できたのですが、
Viewにてデータを取得して表示させる際に、
post.shop.shop_basic.id
を取得しようとすると
【undefined method `shop_basic' for ...】
とエラーが出てしまいます。
以下のような関係を持つ複数のモデルを用いています。

問題のViewは以下のものです。
#app/views/users/favorite.html.erb
<% @feed_posts.each do |pt| %>

    <p><%= pt.post_title %></p>
    <p><%= pt.shop.shop_basic.id %></p>

<% end %>
Usersコントローラーのfavoriteは以下の様なものです。
 def favorite
    @feed_posts = current_applicant.favorite_posts
  end
モデルは以下のように記述しています。
class Shop < ActiveRecord::Base
  has_one :shop_basic, dependent: :destroy, foreign_key: 'id',autosave: true
  has_one :post, dependent: :destroy, foreign_key: 'id',autosave: true
end

class Post < ActiveRecord::Base
  belongs_to :shop, foreign_key: "id", autosave: true
  has_many :favorites
  has_many :favorite_users, through: :favorites, source: :user
end

class User < ActiveRecord::Base
  has_many :favorites
  has_many :favorite_posts, through: :favorites, source: :post
end

class Fav < ActiveRecord::Base
  belongs_to :user
  belongs_to :post
end

Viewで、
<%= pt.post_title %>
はうまく取得できているようなのですが、なぜこの場合、Postと関係を持つShopの情報が取得できないのでしょうか。
FavoriteとShopにリレーションが直接無いためかと思い、それぞれにhas_manyやbelongs_toなどいろいろ試してはみたのですが、うまくいきません。


どうすればこのリレーションでshopのデータを取得できるでしょうか。
ご教示よろしくお願いいたします。


情報追加ShopBasicのモデルになります。

class SalonBasic < ActiveRecord::Base
  belongs_to :shop, autosave: true, foreign_key: 'id'

  before_create do
   self.id = shop.id
  end

end
# == Schema Information
#
# Table name: shops
#
#  id                     :integer          not null, primary key
#  email                  :string           default(""), not null
#  encrypted_password     :string           default(""), not null
#  number_of_post         :integer          default(1), not null
#  reset_password_token   :string
#  reset_password_sent_at :datetime
#  remember_created_at    :datetime
#  sign_in_count          :integer          default(0), not null
#  current_sign_in_at     :datetime
#  last_sign_in_at        :datetime
#  current_sign_in_ip     :inet
#  last_sign_in_ip        :inet
#  created_at             :datetime         not null
#  updated_at             :datetime         not null
#
# Indexes
#
#  index_salons_on_email                 (email) UNIQUE
#  index_salons_on_reset_password_token  (reset_password_token) UNIQUE
#
# == Schema Information
#
# Table name: shop_basics
#
#  id                      :integer          not null, primary key
#  shop_name              :string           default(""), not null
#  shop_hp_address        :string
#  representive_name       :string
#  contact_personnel_name  :string
#  farm_name               :string
#  postal_code             :string
#  farm_prefectures        :string
#  farm_address            :string
#  use_email               :string           default(""), not null
#  phone_number            :string
#  contact_personnel_phone :string
#  created_at              :datetime         not null
#  updated_at              :datetime         not null
#
他のページのViewではshop_basicの値もうまく取得できているので、以下のfavoriteアクションが悪さをしているのかなと思ってはいるのですが…
favorite_postsとsalonがリレーションを持てていないみたいです。

 def favorite
    @feed_posts = current_applicant.favorite_posts
  end
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • hello-world

    2015/07/31 21:25

    shopからshop_basicへのリンクが辿れないようなので、
    `ShopBasic`クラスと shops テーブルと shop_basics テーブルの構造も記述していただけると助かります

    キャンセル

回答 1

checkベストアンサー

+2

通常、リレーションを持つモデルの場合、
リレーション先のIDを格納するカラムがあるはずなのですが、
一見したところそれがないのが原因のように思えます。

一般的なリレーションの場合以下の様なカラム構成になります。
# model定義
class ShopBasic < ActiveRecord::Base
  belongs_to :shop # class_name: Shop, foreign_key: :shop_id
end

class Shop < ActiveRecord::Base
  has_one :shop_basic
end

# スキーマ
create_table :shop_basic do |t|
  t.integer :shop_id
  # 以下略
end
Railsの規約上、belongs_to関連にあるモデル側に、
belongs_toで対象としているクラスの名をアンダースコア化したものに_idを追加したカラムを持たせ、
そこに関連先のid属性の値を格納するのがデフォルトとなっています。
特にclass_name,foreign_keyオプションを指定しない場合、
上記ルールで実装されているものとして、フレームワーク側は判断します。

質問に書いてあるソースではSalonBasicとなっていますが、多分、ShopBasicだと解釈して
1.shop_basicにshopのid属性を格納するカラムがない
2.belongs_toで指定しているオプションがおかしい
(自id属性を格納するカラムにリレーション先のid属性を格納するように設定されている)
belongs_to :shop, autosave: true, foreign_key: 'id'
これだと、自分のテーブルのidカラムに参照先のidを格納しているという定義になってしまうので、正常なリレーションが作れないように思われます。

この辺を押さえて、再度ソースを見直してみてはどうでしょう?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/08/01 09:59

    互いにforeign_keyでIDを指定して関係を持たせてはいたのですが、そこがエラーの原因になっているかもしれないですね><
    見なおしてみます!ありがとうございましたm(__)m

    キャンセル

  • 2015/08/01 10:20

    railsのリレーションは、リレーション先のidがどこかに格納されていないと実現できないので、そこのあたりを理解するのが大事だと思います。
    自テーブル参照なんかのちょっと面倒なリレーションを調べて見ると、foreign_keyと格納カラムの関係の理解が深まると思いますよ。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • トップ
  • Rubyに関する質問
  • 【Rails】多対多の関係において、親モデルのデータ取得が出来ないです。お気に入り機能実装で躓いています。