How to parameterize enum? I want to use my enum value in method any? to check true or false for my ActiveRecord
I have method is_any? to check my ActiveRecord
def is_any? status
album.voice_guides.all_except(params[:ids]).any?(&status?)
end
And call is_any? in this method
def verify_bulk_destroy
return if album.pending?
if album.publish?
raise Api::Error::ControllerRuntimeError, :error unless is_any?
(:publish)
end
end
But it raise error
undefined method `status?' for #<Api::Admin::Albums::PremiumGuidesController:0x0000000000d278>
Did you mean? status
status=
Just change your is_any? method to
def is_any?(status)
album.voice_guides.all_except(params[:ids]).any? { |guide| guide.status == status }
end
which will load all records into memory first as your method did before.
Or to this when you want to check the condition in the database without loading the records into memory which might be faster depending on your needs:
def is_any?(status)
album.voice_guides.all_except(params[:ids]).where(status: status).exists?
end
Related
I create a method which is supposed to send me a boolean.
But within it there is a loop who send also boolean.
Sometimes the loop send true sometimes false and I would like my method to send true as soon there is one true.
def update_with_former_email?(update_email)
self.versions.each do |version|
next if version.object.nil?
version.object.include?(update_email)
end
end
For the moment when I call my method like:
person.update_with_former_email?("orsay#gmail.com")
it sends me the whole object self.versions
each returns the object it was called upon, i.e. self. To return an actual boolean value derived from include?, you can use return:
def update_with_former_email?(update_email)
self.versions.each do |version|
next if version.object.nil?
return true if version.object.include?(update_email)
end
return false
end
or better use any? instead of each:
def update_with_former_email?(update_email)
self.versions.any? do |version|
version.object.present? && version.object.include?(update_email)
end
end
I tried rewriting this function numerous ways to get around this error, however, I want to defer to other experts before I disable the cop around it.
def numeric?(obj)
obj.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true
end
This is used like so:
def index
if params[:job_id] && numeric?(params[:job_id])
This issue was solved via: Checking if a variable is an integer
Update trying:
def numeric?(string)
!!Kernel.Float(string)
rescue TypeError, ArgumentError
false
end
Reference How do I determine if a string is numeric?
New error:
def numeric?(arg)
!/\A[+-]?\d+\z/.match(arg.to_s).nil?
end
Passes all Rubocop tests from a default configuration. Complete gist with tests at https://gist.github.com/aarontc/d549ee4a82d21d263c9b
The following code snippet does the trick:
def numeric?(arg)
return false if arg.is_a?(Float)
return !Integer(arg).nil? rescue false
end
Returns false for the following: 'a', 12.34, and '12.34'.
Returns true for the following: '1', 1.
You can write the method
def numeric?(obj)
obj.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/).nil?
end
You really don't need to do nil comparisons and then based on the decision returning true/false. #nil? method does it for you.
Given the following associations:
User has_many Ultimate_Source
User has_many Budget_Source
How do I create the following method:
def foo(source)
user = User.find(1)
user.source.id
end
such that
foo(ultimate_sources)
returns:
user.ultimate_sources.id
thanks.
if source == :ultimate_sources or source == :budget_sources then the following should work.
user.send(source).id
if source is a string you can always convert it to a symbol using source.to_sym.
The send method takes a symbol representing the name of a method and sends the message to that object to execute that method and return what the method returns.
http://ruby-doc.org/core-2.1.2/Object.html#method-i-send
You can use the method .send:
def foo(source)
user = User.find(1)
user.send(source.to_s).id
end
Or the method .try (will not raise a NoMethodError if source is not a method of User):
def foo(source)
user = User.find(1)
user.try(source.to_s).id
end
But I really hope that source is not something coming from the user's input. What if I send delete as value of source variable? It would delete the user ...
I highly recommend you to limit the possible methods, in your case it could be something like this:
def foo(source)
user = User.find(1)
user.try("#{source.gsub('_sources', '')}_sources").try(:id)
end
This code version protects you to send destroy as the source value:
foo('ultimate_sources') # => user.ultimate_sources.id
foo('destroy') # => nil
foo('destroy_sources') # => nil
foo('budget') # => user.budget_sources.id
You could also put in a guard clause to be safe.
def foo(source)
return if (source != 'ultimate_sources') || (source != 'budget_sources')
user = User.find(1)
user.send(source).id
end
I am at a loss as to why this is happening. I have the following function:
def as_json(options = {})
json = {
:id => id,
# ... more unimportant code
}
unless options[:simple]
# ... more unimportant code
end
json
end
It works most of the time, but in one particular partial where I call this:
window.JSONdata = <%= #day.to_json.html_safe %>
I get the following error:
ActionView::Template::Error (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]):
Pointing to the line "unless options[:simple]". As far as I can tell, the options hash is nil - thus the method is ignoring the default param assignment. WHY? I can fix this by changing the method to:
def as_json(options)
options ||= {}
json = {
:id => id,
# ... more unimportant code
}
unless options[:simple]
# ... more unimportant code
end
json
end
Does this make any sense to anyone!? Most appreciative for your help.
This is because you're using to_json, which has a default options of nil. to_json will eventually call as_json and pass the nil as options.
Here's where it happens on the Rails source code. First, to_json is defined with the default options of nil.
# https://github.com/rails/rails/blob/v3.0.7/activesupport/lib/active_support/core_ext/object/to_json.rb#L15
def to_json(options = nil)
ActiveSupport::JSON.encode(self, options)
end
Eventually it will arrive here.
# https://github.com/rails/rails/blob/v3.0.7/activesupport/lib/active_support/json/encoding.rb#L41
def encode(value, use_options = true)
check_for_circular_references(value) do
jsonified = use_options ? value.as_json(options_for(value)) : value.as_json
jsonified.encode_json(self)
end
end
As you see, as_json is called with value.as_json(options_for(value)) and options_for(value) will return the default value of to_json, which is nil.
To check if buyer.save is going to fail I use buyer.valid?:
def create
#buyer = Buyer.new(params[:buyer])
if #buyer.valid?
my_update_database_method
#buyer.save
else
...
end
end
How could I check if update_attributes is going to fail ?
def update
#buyer = Buyer.find(params[:id])
if <what should be here?>
my_update_database_method
#buyer.update_attributes(params[:buyer])
else
...
end
end
it returns false if it was not done, same with save. save! will throw exceptions if you like that better. I'm not sure if there is update_attributes!, but it would be logical.
just do
if #foo.update_attributes(params)
# life is good
else
# something is wrong
end
http://apidock.com/rails/ActiveRecord/Base/update_attributes
Edit
Then you want this method you have to write. If you want to pre check params sanitation.
def params_are_sanitary?
# return true if and only if all our checks are met
# else return false
end
Edit 2
Alternatively, depending on your constraints
if Foo.new(params).valid? # Only works on Creates, not Updates
#foo.update_attributes(params)
else
# it won't be valid.
end
The method update_attributes returns false if object is invalid. So just use this construction
def update
if #buyer.update_attributes(param[:buyer])
my_update_database_method
else
...
end
end
If your my_update_database_method has to be call only before update_attributes, then you shoud use merge way, probably like this:
def update
#buyer = Buyer.find(params[:id])
#buyer.merge(params[:buyer])
if #buyer.valid?
my_update_database_method
#buyer.save
else
...
end
end
This may not be the best answer, but it seems to answer your question.
def self.validate_before_update(buyer)#parameters AKA Buyer.validate_before_update(params[:buyer])
# creates temporary buyer which will be filled with parameters
# the temporary buyer is then check to see if valid, if valid returns fail.
temp_buyer = Buyer.new
# populate temporary buyer object with data from parameters
temp_buyer.name = buyer["name"]
# fill other required parameters with valid data
temp_buyer.description = "filler desc"
temp_buyer.id = 999999
# if the temp_buyer is not valid with the provided parameters, validation fails
if temp_buyer.valid? == false
temp_buyer.errors.full_messages.each do |msg|
logger.info msg
end
# Return false or temp_buyer.errors depending on your need.
return false
end
return true
end
you'd better check it in your model through a before_save
before_save :ensure_is_valid
private
def ensure_is_valid
if self.valid?
else
end
end
I've run into the same scenario - needed to know if record is valid and do some actions before update save. I've found out that there is assign_attributes(attributes) method which update method uses before save. So nowadays it's likely correct to do:
def update
#buyer = Buyer.find(params[:id])
#buyer.assign_attributes(params[:buyer])
if #buyer.valid?
my_update_database_method
#buyer.save
else
...
end
end