Placeholders in order method of ActiveRecord - ruby-on-rails

How do I do this in rails?
User.order("abs(height-?)",val)
Seems like placeholders are not supported in order method, is there some lower level method I can use to process plceholders?

I think this might be one place where you should actually use string interpolation, but use whitelisting to ensure val does not contain anything weird
if User.column_names.include? val
User.order("abs(height - #{val})")
else
#some error handling
end

Related

Shortcut for conditional variable manipulation in Ruby/Rails

One of the parameters my API controller receives has a big key name and I need to convert it from string to integer, if it is present, before sending it to the model to be persisted. Usually I would do one of the following:
params[:really_big_key_name] = params[:really_big_key_name].to_i unless params[:really_big_key_name].blank?
or
params[:really_big_key_name] = params[:really_big_key_name].present? ? params[:really_big_key_name].to_i : nil
As you can see, the code line becomes big, with more than 80 characters, and I want to stick with Ruby best practices. Is there a shorter, more Ruby way to do the same? Maybe "in place" methods. Something like arrays do with bang methods. Unfortunately, to_i! does not exist for strings, which is exactly what I need.
You could do this:
params[:really_big_key_name] = params[:really_big_key_name].try(:to_i)

Rails common method for updating a database field

I am new to rails and I have a task to write a common method that will update a specific database field with a given value. And I should be able to invoke the method from anywhere in the app.(I understand about the security flaw and so on.. But I was asked to do it anyway) In my application controller I tried
def update_my_model_status(model,id,field, value)
#model = model.find(id)
#model.update(field: value)
end
Of course this doesn't work.. How to achieve this? What is the right way to do this? And if it is possible how to pass a model as an argument to a method?
If you're using Rails, why not use Rails?
Compare update_all:
MyModel.where(id: 1).update_all(banned: true)
or maybe update_attribute:
my_model.update_attribute(:banned, true)
to:
update_my_model_status(MyModel, 1, :banned, true)
Notice how, despite being shorter, the first two approaches are significantly more expressive than the last - it is much more obvious what is happening. Not only that, but they are immediately more familiar to any Rails developer off the street, while the custom one has a learning curve. This, combined with the added code from the unnecessary method adds to the maintenance cost of the application. Additionally, the Rails methods are well tested and documented - are you planning to write that, too? Finally, the Rails methods are better thought out - for example, your prototype naively uses attribute validations, but does not check them (which could result in unexpected behavior) and makes more SQL queries than it needs to. It's fine to write custom methods, but let's not write arbitrary wrappers around perfectly fine Rails methods...
Try this:
def update_my_model_status(model,id,field, value)
#model_var = model.capitalize.constantize.find(id)
#model_var.update_attributes(field: value)
end
Instead of just using update you should use update_attributes:
def update_my_model_status(model,id,field, value)
#model_var = model.find(id)
#model.update_attributes(field: value)
end
http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update

Rails manipulate model query

Assume I have params[:foo] = "bar" and some saved object whose attribute = "key.bar"
How can I manipulate Model.where(attribute: params[:foo]) to query for attribute.split(".")[1] ?
I'm not certain if there's a better way, but the first method that popped in my mind is using the LIKE operator. You can write your query thusly:
Model.where("attribute LIKE '%?'", params[:foo])
Note, given the example you posted, I placed the wildcard (%) in that position so that the attribute is match for anything that ends with your parameter. This assumes all your attributes are similar to what you described, but you can of course change it around to your liking.
Also, while I've never used it myself, I understand that the Squeel gem provides this functionality as an operator (described here).
Small change to answer above
Model.where("attribute LIKE '%.?'", params[:foo])
to prevent matching both .bar and .foobar.

How to chain try() and scoped to_s() in Rails?

In a Rails view, one can use try to output only if there is a value in the database, e.g
#model.try(:date)
And one can chain trys if, for example, the output is needed as a string
#model.try(:date).try(:to_s)
But what if I need to call a scoped format? I've tried
#model.try(:date).try(:to_s(:long))
#model.try(:date).try(:to_s).try(:long)
What is the correct syntax for this? And what is a good reference for more explanation?
Thanks
From the fine manual:
try(*a, &b)
[...]
try also accepts arguments and/or a block, for the method it is trying
Person.try(:find, 1)
So I think you want:
#model.try(:date).try(:to_s, :long)
This one won't work:
#model.try(:date).try(:to_s(:long))
because you're trying to access the :to_s symbol as a method (:to_s(:long)). This one won't work:
#model.try(:date).try(:to_s).try(:long)
because you're trying to call the long method on what to_s returns and you probably don't have a String#long method defined.
mu is too short's answer shows the correct usage for the try method with parameters:
#model.try(:date).try(:to_s, :long)
However, if you are using Ruby 2.3 or later, you should stop using try and give the safe navigation operator a try (no pun intended):
#model&.date&.to_s(:long)
The following answer is here for historical purposes – adding a rescue nil to the end of statements is considered bad practice, since it suppresses all exceptions:
For long chains that can fail, I'd rather use:
#model.date.to_s(:long) rescue nil
Instead of filling up my view with try(...) calls.
Also, try to use I18n.localize for date formatting, like this:
l #model.date, format: :long rescue nil
See:
http://rails-bestpractices.com/posts/42-use-i18n-localize-for-date-time-formating
In case you often use try chains without blocks, an option is to extend the Object class:
class Object
def try_chain(*args)
args.inject(self) do |result, method|
result.try(method)
end
end
end
And then simply use #model.try_chain(:date, :to_s)

Is there any way to define a model's attribute as always html_safe?

I have a model called Feature with a variable called body_string, which contains HTML markup I'd like to render, rather than escape.
Every time I reference body_string in my views, I need to use <%=raw or .html_safe. This seems redundant and not-so-DRY.
Is there any way that I can establish once-and-for-all the body_string variable as html_safe?
I'm assuming this would happen in the app/models/feature.rb file, but I can't figure out what the right syntax would be, exactly. I've thought of this:
def body_string
return self.body_string.html_safe
end
But Rails doesn't like it; it raises a stack level too deep exception.
Naturally I could define a variable/method with a different name:
def safe_body_string
return self.body_string.html_safe
end
And then just change all references in the views from body_string to safe_body_string. But somehow this seems almost as un-DRY as simply using raw or .html_safe in the first place.
Any insights to how best to handle this? I feel like there must be something really elegant that I'm just not seeing.
Just use read_attribute to avoid the recursive call to body_string:
def body_string
read_attribute(:body_string).html_safe
end
read_attribute is complemented by write_attribute for setting attributes from within your model.
A note on style: Don't use explicit returns unless you actually need them. The result of the last statement in a method is implicitly the value returned from the method.
While #meager's answer will definitely work, I don't think this logic belongs in a model. Simply because it adds view-level concerns (HTML safeness) to the model layer, which should just include business logic. Instead, I would recommend using a Presenter for this (see http://nithinbekal.com/posts/rails-presenters/ or find a gem for this -- I personally love Display Case). Your presenter can easily override the body_string method and provide the .html_safe designation when displaying in the view. This way you separate your concerns and can continue to get body_string from other models without mixing in the view concern.
Maybe this gem is useful for you. I also wanted to stop repeating html_safe all the time when the content is completely trustable.
http://rubygems.org/gems/html_safe_attribute
Or you can also use this approach,
def body_string
super && super.html_safe
end

Resources