Rails logic not firing on `false` results - ruby-on-rails

Receiving as an API an array of hashes
#request['clients'].each do |client|
validations are being executed on each clientattributes. However, rails logic is failing to fire up on false statements and this ignoring them. Example validation:
def client_type_ok
if #this_client['type'] == "ADT" || #this_client['type'] == "CHD"
true
else
false
#error_code_39 = true
end
end
The controller action wants to execute only when true conditions are met:
if client_type_ok && client_type_ok
However Rails.logger is clearly confirming that this condition is being passed through although false.
Rails.logger.info !#this_client['type'].blank?
Rails.logger.info #this_client['type']
Rails.logger.info "not"
Rails.logger.info #this_client['type'] != "ADT"
Rails.logger.info "ADT"
Rails.logger.info #this_client['type'] == "ADT"
is returning
true
APT
not
true
ADT
` `
The bottom is generated as a blank. The same occurs replacing Rails.logger with p. All logic of this action is ignoring false results. While I can attempt to devise processing cases of fully true cases, this is inconvenient and counter-intuitive.
Thus, there appears to be a meta function which is impeding the handling of false cases. How can this be tracked down? Can Rails.logger logic be step traced?

You're not returning false there
def client_type_ok
if #this_client['type'] == "ADT" || #this_client['type'] == "CHD"
true
else
false # this is not doing anything. Simply ignored.
#error_code_39 = true # result of this assignment will be true.
# and it also is the last expression of the if
# so it becomes the implicit return value of the method
end
end

def client_type_ok
if #this_client['type'] == "ADT" || #this_client['type'] == "CHD"
true
else
false
#error_code_39 = true
end
end
As Sergio mentiond in the above answer,The return value of yur method will be true for the else condtion. You need to swap the places or You can rewrite the above method
def client_type_ok
return true if %w(ADT CHD).include?(#this_client['type'])
#error_code_39 = true
false
end

Related

Assignment Branch Condition size for update_status is too high. [<1, 18, 8> 19.72/17]

How can i fix this, when i try to condition if user.completed? == false or add when "completed" , i will has error
def update_status
status_cont = params[:status_cont]
if user.completed? == false
case status_cont
when "waiting_email_confirm"
user.waiting_email_confirm!
when "email_confirmed"
user.email_confirmed!
when "ready_to_ship"
user.ready_to_ship!
when "shipped"
user.shipped!
when "canceled"
user.canceled!
when "completed"
user.completed!
end
end
end
There's a pattern in your case that you can use to simplify the logic. Something like this:
STATUS_CONTS = %w[canceled completed email_confirmed ready_to_ship shipped waiting_email_confirm]
private_constant :STATUS_CONTS
def update_status
return if !user.completed?
status_cont = params[:status_cont]
raise "Unknown status_cont #{status_cont}" if !status_cont.in?(STATUS_CONTS)
user.send("#{status_cont}!")
end
You'll probably want to handle unknown status_cont values differently but I don't know how the surrounding flow works.

How to implement custom validations for methods called by other methods?

I create a Subscription for a User via the method .create_subscription(plan_title).
That method checks that it's possible to subscribe (not oversubscribed plan or archived subscription) via the method .plan_subscribable?(plan).
This method does either return true or false, but I would like it to return an error message as well that could be passed to the user if false.
How and where do I implement these validation errors?
class User
def plan_subscribable?(plan)
users_subscribed = Subscription.where(plan_id: plan.id).size
return false unless users_subscribed <= plan.quantity
return false unless plan.archived == false
return true
end
def create_subscription(plan_title)
plan = Plan.where(title: plan_title).first
if plan_subscribable?(plan)
Subscription.create(...)
end
end
end
You could modify plan_subscribable? to return a boolean true or a string containing the specific error message:
def plan_subscribable?(plan)
return 'The number of users cannot be higher than the plan quantity' unless users_subscribed <= plan.quantity
return 'Archived plans are not subscribable' unless plan.archived == false
return true
end
Then, evaluate whether the returned value from plan_subscribable? is true. If it is not, the statement is implicitly false and you can use the returned value as the error message:
def create_subscription(plan_title)
plan = Plan.where(title: plan_title).first
subscribable_or_error = plan_subscribable?(plan)
if subscribable_or_error === true
Subscription.create(...)
else
error_message = subscribable_or_error
end
end

Override setter doesn't work with update_attributes

I'm making an task-manager and have an boolean attribute for 'finished'. I've tried to override the setter to implement an 'finished_at' date when i toggle 'finished' to true.
But i getting some mixed result. It doesn't work in browser but it will work in my rspec test.
Please help me out.
class TasksController < ApplicationController
# ...
def update
# ..
if #task.update_attributes(params[:task]) # where params[:task][:finished] is true
# ...
end
class Task < ActiveRecord::Base
#...
def finished=(f)
write_attribute :finished, f
write_attribute :finished_at, f == true ? DateTime.now : nil
end
end
# and in rspec i have
describe "when marked as finished" do
before { #task.update_attributes(finished: true) }
its(:finished_at) { should_not be_nil }
its(:finished_at) { should > (DateTime.now - 1.minute) }
describe "and then marked as unfinished" do
before { #task.update_attributes(finished: false) }
its(:finished_at) { should be_nil }
end
end
in browser it executes "UPDATE "tasks" SET "finished" = 't', "updated_at" = '2012-10-02 18:55:07.220361' WHERE "tasks"."id" = 17"
and in rails console i got the same with update_attributes.
But in rspec with update_attributes i get "UPDATE "tasks" SET "finished" = 't', "finished_at" = '2012-10-02 18:36:47.725813', "updated_at" = '2012-10-02 18:36:51.607143' WHERE "tasks"."id" = 1"
So I use the same method but it's only working in rspec for some reson...
using latest rails and latest spec (not any rc or beta).
Solution
Not mush i did need to edit. Thanks #Frederick Cheung for the hint.
I did notice i did like "self[:attr]" more than "write_attribute". Looks better imo.
def finished=(value)
self[:finished] = value
self[:finished_at] = (self.finished? ? Time.now.utc : nil)
end
Your setter is passed the values as they are passed to update_attributes. In particular when this is triggered by a form submission (and assuming you are using the regular rails form helpers) f will actually be "0" or "1", so the comparison with true will always be false.
The easiest thing would be to check the value of finished? after the first call to write_attribute, so that rails can convert the submitted value to true/false. It's also unrubyish to do == true - this will break if the thing you are testing returns a truthy value rather than actually true (for example =~ on strings returns an integer when there is a match)
You could use ActiveRecord Dirty Tracking to be notified of this change.
http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
class Task < ActiveRecord::Base
before_save :toggle_finished_at
def toggle_finished_at
if finished_changed?
before = changes['finished'][0]
after = changes['finished'][1]
# transition from finished => not-finished
if before == true && after == false
self.finished_at = nil
end
# transition from not finished => finished
if before == false && after == true
self.finished_at = Time.now.utc
end
end
end
end
This is a use case for a state machine. You call a :finish! event (a method) which is configured to change the state and to do whatever else needed.
https://github.com/pluginaweek/state_machine/

Proper identification of admin for admin_data on Heroku

We have everything installed correctly, but when an admin goes to /admin_data it throws "not authorized".
heres the relevant code in config/initializers/admin_data.rb
AdminData.config do |config|
config.is_allowed_to_view = lambda {|controller| return true if current_user.admin = true }
config.is_allowed_to_update = lambda {|controller| return true if current_user.admin = true }
end
Could be the condition you're using to check equality:
if current_user.admin = true #will always be true
vs
if current_user.admin == true #will check the equality of being true
You might consider just:
if current_user.admin
since nil or false will be NOT == true

strange nil object result

I have a module:
module Voteable
def has_up_vote_of user
return ! self.votes.select{|v| v.user.id == user.id && v.value == 1}.empty?
end
def has_down_vote_of user
return ! self.votes.select{|v| v.user.id == user.id && v.value == -1}.empty?
end
end
Which is mixed into a model:
class Comment < ActiveRecord::Base
include Voteable
end
In a controller code, there is a check:
has_up_vote = #voteable.has_up_vote_of #user
has_down_vote = #voteable.has_down_vote_of #user
#voteable and #user are existing model items, found in a DB.
Suppose, voteable item has up-vote of user. After executing the code, has_up_vote will be equal to true, and has_down_vote will be nil.
Why nil, instead of false ?
I have used several variations of methods, but the problem is the same. Even this gives me the same effect:
def has_up_vote_of user
has = self.votes.select{|v| v.user.id == user.id && v.value == 1}.empty?
return !has.nil? && has
end
Posssible, i'm misunderstanding something, but this behavior is strange
Update
I've noticed very strange behaviour.
When i change methods to trivial:
def has_up_vote_of user
return false
end
def has_down_vote_of user
return false
end
They both returns nil, when i debug the app.
But, from console, they returns false.
It's more stange, because i cannot do anything with these results. These code is not working:
has_up_vote = false if has_up_vote.nil?
has_down_vote = false if has_down_vote.nil?
I think that the debugging environment you're running in is interfering with the actual value of has_down_votes. The select method should never return nil as defined.
Instead of !{}.empty? you could use {}.present?
Its more readable and the output will always be true/false only
I know this doesn't get to the root cause of your strange problem, but it should give you the results you want. Instead of
return ! self.votes.select{|v| v.user.id == user.id && v.value == -1}.empty?
try
return !!self.votes.select{|v| v.user.id == user.id && v.value == -1}.any?
The double exclamation point is intentional -- it will cause nil to become false. (!arr.empty? is equivalent to arr.any? which is equivalent to !!arr.any? -- except the last one converts the nil to false)

Resources