1

Ruby on Rails の学習経験は数週間、または 1 か月近くあります。関連オブジェクトを介してメソッドを取得できない理由を理解したいと思っています。

私は、スタンだけではなく、ユーザーに関連付けられた関連オブジェクトを取得しようとしています。

user.profile.create

user.profile.create!

user.profile.build

代わりに、RSpec エラー メッセージが表示されます。NoMethodError: nil:NilClass の未定義のメソッド `build'

よろしくお願いします

# == Schema Information
#
# Table name: users
#
#  id         :integer         not null, primary key
#  email      :string(255)
#  created_at :datetime        not null
#  updated_at :datetime        not null
#

class User < ActiveRecord::Base
  attr_accessible :email
  has_one :profile

  before_save { |user| user.email = email.downcase }

  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
end

.

    # == Schema Information
    #
    # Table name: profiles
    #
    #  id         :integer         not null, primary key
    #  given_name :string(255)
    #  surname    :string(255)
    #  user_id    :integer
    #  created_at :datetime        not null
    #  updated_at :datetime        not null
    #

    class Profile < ActiveRecord::Base
      attr_accessible :given_name, :surname #, :user_id
      belongs_to :user

      validates :user_id, presence: true
    end

.

    smileymike@ubuntu:~/rails_projects/bffmApp$ bundle exec guard
    Guard uses Libnotify to send notifications.
    Guard is now watching at '/home/smileymike/rails_projects/bffmApp'
    Starting Spork for RSpec
    Using RSpec
    Preloading Rails environment
    Loading Spork.prefork block...
    Spork is ready and listening on 8989!
    Spork server for RSpec successfully started
    Guard::RSpec is running, with RSpec 2!
    Running all specs
    Running tests with args ["--drb", "-f", "progress", "-r", "/home/smileymike/.rvm/gems/ruby-1.9.3-p194/gems/guard-rspec-0.7.2/lib/guard/rspec/formatters/notification_rspec.rb", "-f", "Guard::RSpec::Formatter::NotificationRSpec", "--out", "/dev/null", "--failure-exit-code", "2", "spec"]...
    ......FFFFFFFF...............

    Failures:

      1) Profile 
         Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") }
         NoMethodError:
           undefined method `build' for nil:NilClass
         # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>'

      2) Profile 
         Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") }
         NoMethodError:
           undefined method `build' for nil:NilClass
         # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>'

      3) Profile 
         Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") }
         NoMethodError:
           undefined method `build' for nil:NilClass
         # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>'

      4) Profile 
         Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") }
         NoMethodError:
           undefined method `build' for nil:NilClass
         # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>'

      5) Profile 
         Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") }
         NoMethodError:
           undefined method `build' for nil:NilClass
         # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>'

      6) Profile user 
         Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") }
         NoMethodError:
           undefined method `build' for nil:NilClass
         # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>'

      7) Profile when user_id is not present 
         Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") }
         NoMethodError:
           undefined method `build' for nil:NilClass
         # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>'

      8) Profile accessible attributes should not allow access to user_id
         Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") }
         NoMethodError:
           undefined method `build' for nil:NilClass
         # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>'

    Finished in 1.56 seconds
    29 examples, 8 failures

    Failed examples:

    rspec ./spec/models/profile_spec.rb:27 # Profile 
    rspec ./spec/models/profile_spec.rb:28 # Profile 
    rspec ./spec/models/profile_spec.rb:29 # Profile 
    rspec ./spec/models/profile_spec.rb:30 # Profile 
    rspec ./spec/models/profile_spec.rb:33 # Profile 
    rspec ./spec/models/profile_spec.rb:31 # Profile user 
    rspec ./spec/models/profile_spec.rb:37 # Profile when user_id is not present 
    rspec ./spec/models/profile_spec.rb:41 # Profile accessible attributes should not allow access to user_id
    Done.

    > 

.

require 'spec_helper'

describe Profile do

#  before do
    # This code is wrong but it works
#    @profile = Profile.new(given_name: "Michael", surname: "Colin", user_id: user.id)
#  end
#  but I am attempting to create a profile via User/Profile assoications
  let(:user) { FactoryGirl.create(:user) }
  before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") }

  subject { @profile }

  it { should respond_to(:given_name) }
  it { should respond_to(:surname) }
  it { should respond_to(:user_id) }
  it { should respond_to(:user) }
  its(:user) { should == user }

  it { should be_valid }

  describe "when user_id is not present" do
    before { @profile.user_id = nil }
    it { should_not be_valid }
  end

  describe "accessible attributes" do
    it "should not allow access to user_id" do
      expect do
        Profile.new(user_id: user_id)
      end.should raise_error(ActiveModel::MassAssignmentSecurity::Error)
    end    
  end  
end
4

1 に答える 1

3

has_one は、ユーザーに対して build_profile メソッドを提供します。詳細については、http: //guides.rubyonrails.org/association_basics.html#has_one-association-referenceを参照してください。

user.profile.build を実行できない理由は、プロファイルがないためです。したがって、user.build は nil を返し、nil にプロファイルの作成を依頼しても意味がありません。これは、コレクションが空の場合でも、out が常にオブジェクトのコレクションを返す has_many のケースとは異なり、コレクションに別のメンバーを作成するように要求できます。has_one アクセサーが nil 以外の「私はここにいません」という値を返すことを想像するのは簡単です。これにより、シナリオが有効になりますが、他の問題が発生する可能性があります (主に、そのような値は false ではないため、Rubyesque コードが少なくなることは間違いありません)。

于 2012-05-29T02:56:11.260 に答える