Railscasts put out a great episode on refactoring. One method is to move complex controller logic into service objects instead of pushing it down the model. In one service object, the following code is used:
class PasswordReset
attr_reader :user
def self.from_email(email)
new User.find_by_email(email)
end
def self.from_token(token)
new User.find_by_password_reset_token!(token)
end
...
end
What does the new
key word serve in both method bodies? new User.find_by_
. How is that different from User.find_by_
?
Here's the calling code:
def create # controller
password_reset = PasswordReset.from_email(params[:email])
if password_reset.user
password_reset.send_email
redirect_to root_url, notice: "Email sent with password reset instructions."
else
redirect_to new_password_reset_url, alert: "Email address does not match a user account."
end
end
Also, why the attr_reader :user
needed?
To create a new object (or instance), we call new on the class. Unlike other languages, new isn't a keyword of the language itself, but a method that gets called just like any other. In order to customize the newly created object, it is possible to pass arguments to the new method.
Defining & Calling the method: In Ruby, the method defines with the help of def keyword followed by method_name and end with end keyword. A method must be defined before calling and the name of the method should be in lowercase. Methods are simply called by its name.
You can create objects in Ruby by using the method new of the class. The method new is a unique type of method, which is predefined in the Ruby library. The new method belongs to the class methods. Here, cust1 and cust2 are the names of two objects.
The code def hi starts the definition of the method. It tells Ruby that we're defining a method, that its name is hi . The next line is the body of the method, the same line we saw earlier: puts "Hello World" . Finally, the last line end tells Ruby we're done defining the method.
the classname is implicit in self methods. The code could have be written like:
def self.from_email(email)
PasswordReset.new User.find_by_email(email)
end
To answer the 2nd half of your question, attr_reader
defines an instance variable and a reader method (aka getter method if you're coming from java or c#). Putting it all together, you could have written it as :
class PasswordReset
def user
@user
end
def self.from_email(email)
PasswordReset.new User.find_by_email(email)
end
def self.from_token(token)
PasswordReset.new User.find_by_password_reset_token!(token)
end
...
end
This is assuming PasswordReset#initialize takes a User as a parameter, and sets @user accordingly
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With