Guard clause in Rails unless - ruby-on-rails-5

I am using Rubocop in my rails application and it suggests Use a guard clause instead of wrapping the code inside a conditional expression for this. Plz suggest a clean way to rewrite it.
def exist
#account = Account.find_by(id: params[:id])
unless #account.present?
render json: { error: 'Account is not available' }, status: :not_found
end
end

RuboCop is suggesting a change such as this:
def exist
#account = Account.find_by(id: params[:id])
render json: { error: 'Account is not available' }, status: :not_found unless #account.present?
end
But whether this is more 'clean' is subjective.

Related

How to return the correct fields in Rails API?

I have these two tables - User, Accounts.
User contains an authentication key,
Accounts contains the list of accounts.
I am trying to get the list of accounts for the user if the authentication key is correct.
So in the controller I have -
def show
#user = User.where(authentication_token: params[:authentication_token])
render json: #user.as_json(
only: [:email, :id, :authentication_token]
),
status: :created
end
This would just return the user details. How can i edit it so it first checks if the user exists with that Authentication_token, and then uses the UserID, in the accounts table to get the list of accounts ?
Your question is a little unclear: What is the desired behaviour if the authentication_token is not correct? Raise an exception? Redirect somewhere? Display a flash message? ...
You could, for example, do something like this:
def show
if authenticated_user
render json: authenticated_user.accounts.as_json(
only: [:id, :foo, :bar]
),
status: :ok
else
render json: { errors: { authentication_token: 'Invalid' } },
status: :unauthorized
end
end
private
def authenticated_user
#authenticated_user ||= User.find_by(
authentication_token: params[:authentication_token]
)
end

Rspec test not passing because of model name?

I'm testing my User model and they can have many aliases:
describe User do
describe "alias associations" do
before { #user.save }
let!(:first_alias) do
FactoryGirl.create(:alias, user: #user, created_at: 1.day.ago)
end
let!(:second_alias) do
FactoryGirl.create(:alias, user: #user, created_at: 1.hour.ago)
end
it "User should have many aliases" do
#user.aliases.should == [first_alias, second_alias]
end
it "should destroy associated aliases" do
aliases = #user.aliases.dup
#user.destroy
aliases.should be_empty
aliases.each do |aliases|
Alias.find_by_id(alias.id).should be_nil
end
end
end
end
My Rspec test is throwing me a loop though. I have a model named Alias and it's giving me this error:
syntax error, unexpected keyword_alias, expecting ')' (SyntaxError)
Alias.find_by_id(alias.id).should be_nil
When I do alias.id it's considered to be a problem.
Why am I getting this error? Is it because of my use of Alias as a model? Changing it to something else gets the test to run.
there are several problems here:
don't use alias, because it's a reserved word
you are passing aliases to the block instead of alias

Rails current_page? "fails" when method is POST

I have a really simple problem. I have a page of reports and each report has its own tab. I'm using current_page? to determine which tab should be highlighted. When I submit any report, current_page? doesn't seem to work anymore, apparently because the request method is POST.
Is this the intended behavior of current_page? I have a hard time imagining why that would be the case. If it is, how do people normally get around this problem?
Here's an example of a current_page? call:
<li><%= link_to "Client Retention", reports_client_retention_path, :class => current_page?(reports_client_retention_path) ? "current" : "" %></li>
All right, it looks like I figured out the answer to my own question about 5 minutes after putting up a bounty. It looks like current_page? will always return false on POST.
Here's the source code for current_page?:
# File actionpack/lib/action_view/helpers/url_helper.rb, line 588
def current_page?(options)
unless request
raise "You cannot use helpers that need to determine the current " "page unless your view context provides a Request object " "in a #request method"
end
return false unless request.get?
url_string = url_for(options)
# We ignore any extra parameters in the request_uri if the
# submitted url doesn't have any either. This lets the function
# work with things like ?order=asc
if url_string.index("?")
request_uri = request.fullpath
else
request_uri = request.path
end
if url_string =~ %r^\w+:\/\//
url_string == "#{request.protocol}#{request.host_with_port}#{request_uri}"
else
url_string == request_uri
end
end
I don't really understand why they would have gone out of their way to make current_page? work only for GET requests, but at least now I know that that's the way it is.
You could create a new current_path? method in your ApplicationHelper:
def current_path?(*paths)
return true if paths.include?(request.path)
false
end
Pass in one or more paths and it returns true if any match the user's current path:
current_path?('/user/new')
current_path?(root_path)
current_path?(new_user_path, users_path '/foo/bar')
Or, you can create a new current_request? helper method to check the Rails controller + action:
def current_request?(*requests)
return true if requests.include?({
controller: controller.controller_name,
action: controller.action_name
})
false
end
Pass in one or more controller + action and it returns true if any match the user's current request:
current_request?(controller: 'users', action: 'new')
current_request?({controller: 'users', action: 'new'}, {controller: 'users', action: 'create'})
==UPDATE==
Ok, I decided to make using current_request? a little less verbose by not requiring that you type out the controller when you are trying to match multiple actions:
def current_request?(*requests)
requests.each do |request|
if request[:controller] == controller.controller_name
return true if request[:action].is_a?(Array) && request[:action].include?(controller.action_name)
return true if request[:action] == controller.action_name
end
end
false
end
Now you can do this:
current_request?(controller: 'users', action: ['new', 'create'])
I was having the same problem when using POST. My solution was to do something like this
def menu_item link_text, link_path
link_class = (request.original_url.end_with? link_path) ? 'active' : ''
content_tag :li, link_to(link_text, link_path), class: link_class
end
where link_path is just url_for(action: 'action', controller: 'controller')

validates_acceptance_of still saves the record

I am using ruby 1.9.2-p180, rails 3.0.7. I have used validates_acceptance_of since the user has to agree to our terms and conditions. We don't have a column for this, but I understand that "If the database column does not exist, the terms_of_service attribute is entirely virtual. " from http://ar.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M000082
Anyway, I double checked this by smoke testing the app manually and I see from the logs that the record is still inserted into the db, which is weird because upon submitting the form, I am redirected back to the form with the error: "Must agree to terms and conditions"(which made me think it worked before)
Am I doing something wrong here?
_form.haml:
%label.checkbox-label{:for => "operator_terms_and_conditions"}
= f.check_box :terms_and_conditions
I agree to
= link_to "Terms and Conditions", operator_terms_path, :target => "_blank"
operators_controller:
def create
user_params = params[:operator][:user]
user_params.merge!(:login => user_params[:email])
#password = params[:operator][:user][:password]
Operator.transaction do # don't save User if operator is invalid
#operator = Operator.create(params[:operator])
end
respond_to do |format|
unless #operator.new_record?
UserMailer.operator_confirmation_email(#operator, #password).deliver
UserMailer.operator_registration_admin_notification_email(#operator).deliver
UserSession.create(#operator.user)
format.html {redirect_to new_operator_aircraft_path}
else
format.html { render :action => "new" }
end
end
end
and in the model:
validates_acceptance_of :terms_and_conditions
Found the answer. The problem was not with validates_acceptance_of but rather with how I was saving the data. When an operator was created, a user was also created that was tied to it and it was this user that was being inserted into the db.
This happens because although the operator was being rolled back(because it wasn't valid) the user was still created(because it was not in a transaction).
I solved this by using nested_transactions:
operator model:
...
User.transaction(:requires_new => true) do
create_user
raise ActiveRecord::Rollback unless self.valid?
end
...

Receiving "unknown method" errors when running RSpec tests against an ActiveRecord model

I'm having a bit of trouble with some RSpec tests on some of my ActiveRecord validations. The test suite looks like this:
describe Event do
context "An Event" do
before do
valid_event_hash = {
:name => 'Blah Blah',
:desc => 'Yadda Yadda Yadda',
:category => 'some category',
:has_partner => false,
:event_abbr => 'BB'
}
#event = Event.new(valid_event_hash)
end
it "should have a name" do
#event.name = ''
#event.should_not be_valid
end
it "should have a description" do
#event.desc = ''
#event.should_not be_valid
end
it "should have an abbreviation no shorter than 2 letters and no longer than 3 letters" do
#event.event_abbr = ''
#event.should_not be_valid
#event.event_abbr = 'BlaBla'
#event.should_not be_valid
#event.event_abbr = 'B'
#event.should_not be_valid
end
after do
#event.destroy
end
end
end
The model is set up so that it should pass all of these validations appropriately. The schema indicates that all of the fields I fill in are present and accounted for. Yet, when I run autotest, the tests fail with the following error:
Failure/Error: #event = Event.new(valid_event_hash)
unknown attribute: event_abbr
I can create the very same #event instance in the console with those values, and it works perfectly. My gut reaction is that, for some reason, the model that the test suite is using doesn't know about the :event_abbr field, but I can't think why that might be. I'm sure I'm missing something, but I'm not sure what it is. Any help would be greatly appreciated.
Did you run your migrations on your test database? E.G.
RAILS_ENV=test rake db:migrate
else, try
rails console test
and try it there.