the12
the12

Reputation: 2415

How does .valid? run even there is no object in front of it (valid? instead of object.valid?)?

Watching Railscasts, more specifically Form Objects. Here is the code.

Controller code:

def create
  @signup_form = SignupForm.new
  if @signup_form.submit(params[:user])
    session[:user_id] = @signup_form.user.id
    redirect_to @signup_form.user, notice: "Thank you for signing up!"
  else
    render "new"
  end
end

Method found on form object:

  class SignupForm 
    def submit(params)
      user.attributes = params.slice(:username, :email, :password, :password_confirmation)
      profile.attributes = params.slice(:twitter_name, :github_name, :bio)
      self.subscribed = params[:subscribed]
      if valid?
        generate_token
        user.save!
        profile.save!
        true
      else
        false
      end
    end
  end

I understand most of the code, but what I don't understand is how .valid? can run without an object written directly in front of it (i.e.: object.valid?)? I tried replicating this with Ruby, but Ruby requires an object to be directly written in front of the method, which leads me to believe this is some sort of Rails magic.

Can someone explain how .valid? runs without an object in front of it , and which object it picks up?

I tried using the following Ruby code and did not work:

array = [1,2,3,4]

def meth
  if is_a?
    puts "is array"
  else
    puts "not array"
  end
end

array.meth => error: wrong number of arguments (given 0, expected 1)

Upvotes: 0

Views: 79

Answers (2)

Holger Just
Holger Just

Reputation: 55778

In the Railscast #416 in question, Ryan includes (among others) the ActiveModel::Validations module into the SignupForm class. This module implements the valid? method for the class.

Now, in Ruby you can always call methods on the current object (i.e. self) without explicitly naming the receiver. If the receiver is unnamed, self is always assumed. Thus, in your submit method, valid? in called on the same instance of the SubmitForm where you originally called submit on.

Upvotes: 4

Jason Spradlin
Jason Spradlin

Reputation: 1427

 class SignupForm 

   def submit(params)
     user.attributes = params.slice(:username, :email, :password, :password_confirmation)
     profile.attributes = params.slice(:twitter_name, :github_name, :bio)
     self.subscribed = params[:subscribed]
     if valid?
       generate_token
       user.save!
       profile.save!
       true
     else
       false
     end
   end

   def valid? // <--- this is what they are calling.
     return true   // this is made up... i am sure it does something
   end
 end

Upvotes: 0

Related Questions