Need to store query result instead of storing query in ActiveRecord - ruby-on-rails

I am having following function to find some of the selected records from public pages.
def find_public_page(title)
#footer_public_pages ||= PublicPage.where(title: %w(welcome_to_toylist terms_of_services buying_a_toy selling_a_toy requesting_a_toy ad_guildelines))
#footer_public_pages.find_by(title: title)
end
what I need is that #footer_public_pages should store the result set in first time and then on next time it will directly hit the find_by query instead of firing two queries.
Any help would be appreciated.

You can try this. I hope this will help You.
def find_public_page(title)
#footer_public_pages ||= PublicPage.where(title: %w(welcome_to_toylist terms_of_services buying_a_toy selling_a_toy requesting_a_toy ad_guildelines)).group_by(&:title)
#footer_public_pages[title].first unless #footer_public_pages[title].blank?
end

The instance variable #footer_public_pages belongs to a class, in this case probably the controller. Because of the way the controller works, every action (i.e. redirect) is going to be a new instance, and will need to set that value again on calling find_public_page. The way it's currently coded would help you if you were calling the method multiple times in the same action (and/or its views), but I doubt that is the case. Instead, if you're trying to keep this variable across multiple pages, you'll want to use a session variable. So you could say:
def find_public_page(title)
session[:footer_public_pages] ||= PublicPage.where(title: %w(welcome_to_toylist terms_of_services buying_a_toy selling_a_toy requesting_a_toy ad_guildelines))
session[:footer_public_pages].find_by(title: title)
end
If you follow this approach, just be warned that these session variables will only be dumped when the user closes the browser (NOT when they navigate away from your site), so you have to be careful in managing them.

Related

rails variables in production environment

I am developing a rails app. Most of the parts work fine, but I got one weird problem when I tried to calculate the time an user used to edit and submit one form.
I thought it would be good to do it in the following order:
1. in the controller "edit" method, record the time the user start to see the form.
2. in the "update" method, record the submit time, then do the math and get how long the user had spent on the form.
class Test
##start_time = 0
##end_time = 0
def edit
##start_time = Time.now
end
def update
##end_time = Time.now
time_used = ##end_time - ##start_time
puts time_used.to_i
end
end
The code above actually works fine while running on my own developing computer, the output is what I expected. But when I upload the code to the production environment(multicore cpus), sometime the output is right, sometime it is not. I debugged the code and found in some case, the ##start_time is set to 0 when submitting the form. I am confused what was going on, maybe I just misused the ## for the variable. Please help me out, any idea would be appreciated, thanks.
Edit:
The problem is solved by adding a virtual attribute to the model as hinted by Vishal. In addition, I added a hidden field in the submit form, and in the strong parameter part added the corresponding parameter to allow it to be passed from edit to update method.
Your solution will create conflicts when more than two users try to edit simultaneously, So basically what idea I have is:
Add one virtual attribute in your model edit_start_time You don't need attribute for endtime because it can be directly fetched by Time.now at any time.
Set edit_start_time value in edit method like:
#model.edit_start_time = Time.now.utc #you can use any
In update method directly calculate edit time like:
total_update_time = Time.now.utc - #model.edit_start_time.utc
If you are unaware of how to create virtual attributes then there are so many questions on StackOverflow as well as docs. I am not explaining how to do it here because its the different topic.
All the best
You're using class variables that can interfer with each other. Your Test class will only ever have one class variable called ##start_time associated with it.
This means if another user sees the form, they will reset the ##start_time for every user currently on it.
To prevent this, use instance varaibles. When a new user sees the form, they will make a new instance variable that is tied to their instance of the class, rather than the class itself. This will allow users to have different start and end times.0
All you need to do is change every ## to #. So instead of ##start_time', try#start_time` throughout your code, and the same for end_time.

Should we use strong params when we update only one attribute?

I'm working on a Rails app and I have several actions( #delete_later, #ban_later and so on) where I only set one attribute from the request parameter( specifically, a reason field for doing that action).
I was wondering if it is ok to do it like this:
def ban_later
#object.reason = params[:object][:reason]
#object.save
end
Or is it a best practice to use strong params even in this situation?
def ban_later
#object.reason = object_params[:reason]
#object.save
end
private
def object_params
params.require(:object).permit(:permitted_1, :permitted_2, :reason)
end
Which of these solutions is the best one? If none of them is, then what's the best solution to my problem?
Later Edit:
The #ban_later, #delete_later actions can indeed set a flag column status but that can be done without receiving it's value from the params hash. Since you will only set one status per method you can simply set the status "pending_delete" when you are in #delete_later and "pending_ban" when you are in #ban_later.
Later Later Edit
Why use #save and not update_attributes directly? Let's say you need to have a if #object.save statement. On the false branch( object not saved) you might still want to render a view where the contents of that #object are used.
First one saves computation.
Second one checks for existence of :object sub-hash, which I think is good for fault-tolerance.
I initially would pick the 1st, but after some thought I liked the second one more.
The simplest answer is that if you only use one parameter in params, and do not pass it to a multi attribute setter like model#create then you don't have to use strong_parameters to get a secure solution.
However, I expect that it is unlikely that this is the case for the whole controller. Where the ban_later method only needs one parameter, other controller methods will need more. In this case the question becomes: "do you want to handle params differently for ban_later to how you use it for the other controller methods?".
Also can you be sure that the functionality will not change, and that when you change the functionality, that you'll remember to change the way params is handled.
Therefore, I would use strong_parameters because it means:
parameters are handled consistently across all methods in the controller.
changes to methods are less likely to expose vulnerabilities as functionality changes.
If you're updating a single attribute, why don't you use the update_attributes method? (update_attribute doesn't invoke validation)
def ban_later
#object.update_attributes reason: params(:reason)
end
private
def params params
params = %i(:permitted_1, :permitted_2, :permitted_3) unless params
params.require(:object).permit params
end
In light of the comments by ReggieB, you could also use the update option:
def ban_later
#object.update reason: params(:reason)
end
As mentioned, Reggie and the other answers explain the schematics of how this works best (IE with mass-assignment etc). Above is actionable code which you're free to use.
The bottom line here is that if you want to keep your application versatile (IE having ultimate extensibility wherever you need), you'll need to adhere to the strong params setup.
The other answers outline how that setup works, and how its functionality is different dependent on what you need.
I have included a trick to make it so you only accept specific params in your params method. I've not tested it extensively, so we may have to refactor it to get the required result.
After strong parameters check why not just update the object? Its just a standart workflow. (Please tell me if there are any reasons not to do that in your situation)
def ban_later
#object.update(object_params)
# dont forget validation check
end
private
def object_params
params.require(:object).permit(:permitted_1, :permitted_2, :reason)
end
In this case it'd be much easier to add more updateble fields.

Controllers in Rails do not "care" how requests are executed

I was reading an article about Rails controllers, can you help me understand please what is meant by the following phrase:
"The best controller is Dilbert-esque: It gives orders without knowing (or caring) how it gets done."
Is it true, in your opinion?
If, for example, I am accessing the index page associated with the subjects controllers, I would define the index method in the subjects_controller.rb rigorously, so I am confused as to what they mean in the article, as I would have thought the opposite.
Any pointers, please?
Thank you and sorry if this is too interpretable. This is the original article: http://betterexplained.com/articles/intermediate-rails-understanding-models-views-and-controllers/
This article is talking about MVC architecture. What's important to take away from an article like this is the fact that Rails is best written with Fat Models and Thin Controllers. This means that you want to have the bulk of your methods/functions in your Model and want to have calls to the functions from your controller. Index is a bad example since typically you're not going to have a lot going on in there.
Your controller for index will typically look something like this
def index
#subjects = Subject.all
end
If you want to scope order for displaying your subjects though, you would do that in your model with a block as follows:
default_scope { order("id DESC") }
A less contrived example might look something like this: Say for example you have an app that accepts input, takes that input and tallies several counters based on what the user entered. Your controller might be named subject_tally and look like this:
def subject_tally
#subject = Subject.find(params[:id])
#subject.winnings += 1
#subject.total_matches += 1
#subject.win_percentage = #subject.winnings.to_f/#subject.total_matches
redirect_to subjects_path
end
THIS IS WRONG. This is a very fat controller and easily moved to the Model where it should be.
If written properly it would look something like this:
subjects_controller.rb: (The Controller)
def subject_tally
#subject = Subject.find(params[:id])
#subject.subject_tally
redirect_to subjects_path
end
subject.rb: (The Model)
def subject_tally
self.winnings += 1
self.total_matches += 1
self.win_percentage =winnings.to_f/total_matches
end
So as you can see, you make only one call from the controller and it "doesn't care" what is actually going on in the backend. It's literally there to pass a value (in this case, the ID of the subject in question) and direct you to another page, in this case, the index.
Furthermore, if you'll notice, you don't need to add that pesky #subject everywhere in your model's subject_tally function... you can reference the attributes of the object just by using self.winnings where you're assigning to an attribute. Ruby is smart enough to know the current subject the method applies to (since you called that function ON a subject from the controller) and in fact you don't even need the self. if you're just retrieving the attributes instead of assigning them... which is why we didn't need self before winnings.to_f or the last line's total_matches.
Very convenient, less code, less time, yay.
The best controller is Dilbert-esque: It gives orders without knowing
(or caring) how it gets done.
means that you should put less logic as you can in the controller,
the controller should only know what to call to get what it needs, and should not know how to carry out a certain action.
In the "Sandy Metz rules" for rails developers (http://robots.thoughtbot.com/sandi-metz-rules-for-developers), she says:
Controllers can instantiate only one object. Therefore, views can only
know about one instance variable and views should only send messages
to that object
only one object could seem a bit extreme, but makes the idea about how much business logic (no logic) you should put in the controller.

Caching DB Result As Global Var

Hi I currently have a helper method that gets Klass.all.map{|m| m.name}. Now I use ids to get the name from the array and if I add more it'll automatically update.
When I use this helper method in a loop in the view, I think it will make multiple queries to get the Klass each time which means a lot of extra work.
I was wondering how I can "cache" this array or if I should be doing this a better way.
Thanks!
SQL caching is done automatically if you're within the same action. You can see here for a more detailed explanation. Just by the way, it would probably be more efficient to use pluck, as in Klass.pluck(:name). This would optimize your SQL query.
Your helper method should look similar to this
def klass_names
#klass_names ||= Klass.all.map{|m| m.name}
end

Class variables VS constants in Rails models

In my application there can be only one current Event which defaults to the nearest date event. I need to retrieve this event in various places and since it doesn't change it makes sense to cache it. There are two ways of doing it known to me:
class Event < ActiveRecord::Base
CURRENT_EVENT = Event.where('starts_on >= ?', Time.now).
order('starts_on ASC').limit(1).first
# OR
def self.current_event
##current_event ||= Event.where('starts_on >= ?', Time.now).
order('starts_on ASC').limit(1).first
end
end
Which one would be the best? Or any other alternatives? I know that using ## class variables is not recommended since they are not thread safe.
I guess you aren't right about your approach: this way your app will keep your cached value forever. New events won't affect it which is completely wrong. It may be the situation when some event already passed but it is still cached as "current".
By the way: limit(1).first does the same as the only first.
Neither first nor second approach are correct. If you define constant - it will find Event, actual on Rails initialization process time. Second approach will not cache your record.
As for me, this is not so fat data to cache.

Resources