18580


多くのlibrary（製品）があり、それぞれのlibraryには多くのdoc（書類が）あります。またそれぞれの製品に多くのpict(画像）がある。  
二つに分けたいのは書類は種類や備考がありますが、pictはサムネールの表示をしたいからです。

library.rb

[code]

    has_many :docs
    has_many :picts
    
[/code]

doc.rb

[code]

    belongs_to :library
    
[/code]

pict.rb

[code]

    belongs_to :library
    
[/code]

としてあります。ここでlibraryコントローラーで

[code]

    def show
      @docs = @library.docs.where(params[:library_id])
    end
    
    def pictshow　#ルーティングの設定はしてある
      @picts = @library.picts.where(params[:library_id])
    end
    
[/code]

になっておりますが、showではエラーが出ないのですが、pictshowで

[code]

    NoMethodError in LibrariesController#pictshow
    undefined method `picts' for nil:NilClass
    
[/code]

になってしまいます。原因が解りません


CC BY-SA 3.0
2015-11-09T11:47:11.610
18576
2015-11-22T04:16:34.000
2015-11-09T23:56:02.813
85
13186
question
ruby-on-rails
Railsで複数のhas_manyを持ったモデルを作りたい


`@picts = @library.picts`
の時点で値が`nil`になっています。該当の`@library`が一枚も`pict`を持っていないためです。


CC BY-SA 3.0
2015-11-09T12:19:22.150
18578
2015-11-09T12:19:22.150
3271
18576
answer


>
[code]

>     NoMethodError in LibrariesController#pictshow
>     undefined method `picts' for nil:NilClass
>  
[/code]

`@library`が`nil`なので`@library.picts`が`NoMethodErrorになっています。

scaffoldで生成したコントローラであればコードはこうなっていると思います。

[code]

    class LibrariesController < ApplicationController
      before_action :set_library, only: [:show, :edit, :update, :destroy]
    
      def show
      end
    
      private
        # Use callbacks to share common setup or constraints between actions.
        def set_library
          @library = Library.find(params[:id])
        end
    end
    
[/code]

`set_library`メソッドによって`@library`に然るべきidのLibraryがロードされるのですが、`set_library`が呼び出されるのは

[code]

      before_action :set_library, only: [:show, :edit, :update, :destroy]
    
[/code]

と、ここで指定されたメソッド(アクション)のみです。自分で追加したメソッドであれば、`before_action`にもそれを追加しないと`@library`は設定されないまま(参照したら`nil`)になります。

ついでに指摘しておきます

[code]

    @docs = @library.docs.where(params[:library_id])
    
[/code]

というコードですが、`@library.docs`は

[code]

    @docs = Doc.where(library_id: @library.id)
    
[/code]

と同じです。多分やりたいことは

[code]

     @docs = @library.docs
    
[/code]

で十分なんじゃないでしょうか。

さらに言うと、`where(params[:library_id])`は多分`where(10)`とかになるので、意図しないクエリになっていると思います。

(暗黙の型変換でSQLとしては`SELECT ... WHERE TRUE`になってるかな？)


CC BY-SA 3.0
2015-11-09T13:31:16.153
18580
2015-11-09T13:31:16.153
5793
18576
answer

[code]

    @library = nil 
    @library.picts 
    #-> undefined method `picts' for nil:NilClass
    
[/code]

になります。  
もし、nilの場合にエラーを出したくないならば、

[code]

     @library = nil 
     @library.try(:picts)
     #-> nil(エラーは出ない)
    
[/code]

を使うことで避ける事ができます。


CC BY-SA 3.0
2015-11-22T04:16:34.000
19156
2015-11-22T04:16:34.000
12758
18576
answer