rails variables in production environment - ruby-on-rails

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.

Related

How do I calculate values for the current user in ruby on rails?

I have an application with a series of tests (FirstTest, SecondTest etc.)
Each test has a calculation set out its relevant model that gets calculated before being saved to the database set out like this:
#first_test.rb
before_save :calculate_total
private
def calculate_total
...
end
I then have an index page for each user (welcome/index) which displays the current user's results for each test. This all works fine, however I want to work out various other things such as each users average score overall etc.
Is it possible to access the current user from the welcome model?
Currently my welcome.rb is accessing the data follows:
#welcome.rb
def self.total
FirstTest.last.total
end
This obviously access the last overall test NOT the last test from the current user.
I feel like I may have just laid the whole application out in a fairly unintelligent manner...
Thanks in advance x
Well you need to save user_id in a column for each record in FirstTest. Then you can find the total for current user
FirstTest.where(:user_id => current_user.id).last.total

Need to store query result instead of storing query in ActiveRecord

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.

create dynamic default values for column in rails?

I am not sure how to go about this, or if there is a better way to do this, but I have a table called leads(many) and it references agent (one).
I want to make a migration that sets a default value for the agent_id column in the leads table. But i want the default value to loop through all the agent ids. Im not sure how to do this!? Should i use a call back, or should i do in migration file?
Here is the actual question im trying to tackle:
When new leads are created assign it to an agent using a “round robin” That way new leads are distributed evenly across all the agents.
Ive attached a screenshot using SUDO code (i know its not functional as is) as to what I am thinking of doing. Any tips?
(Using ruby on rails w/ postgresql)
I think it makes sense to handle this functionality as part of the main app, and not within migration, as there seem to be a significant chunk of functionality to handle.
Probably best to handle it as part of an after_create callback in the Lead model, and use a class variable to track the next agent to be assigned as follows:
class Lead
# Assign the class variable to the first agent
##next_agent = Agent.first
after_create :set_agent
...
private
# Called by the after_create callback
# Sets the agent_id, and updates the ##next_agent class variable
def set_agent
self.agent_id = ##next_agent.id
##next_agent = find_next_agent
end
## Called from the set_agent method
## Finds the next agent based on the current value of ##next_agent
def find_next_agent
##next_agent = Agent.find(##next_agent.id + 1)
##next_agent = Agent.first unless #next_agent
end
end
The find_next_agent logic above is a simplistic example, assuming that all Agent objects have ids that increment by 1, and there are no gaps (i.e. no deletions in the table).

Rails initialize variables in server startup

I want to initialize a variable in rails and use it in a controller's action, but the variable should have a fixed value when the server starts. I have tried defining it inside a controller's action and it get's the same initialized value for every request. For example, i want to initialize a date.now and have the same date after 15 days also.
Update
I am implementing a coming soon page in which a timer is shown 15 days from now. If i implement it in a action inside a controller, it shows new date every time the action is invoked.
Please Help
If you want to create a CONSTANT in rails then you can simply put it into the initializer file. For eg, create a file name constants.rb inside initializer:
#config/initializers/constants.rb
TEST_VALUE = 10
And to access this CONSTANT from your controller, just call for TEST_VALUE. for eg,
#controllers_path/some_controller.rb
.....
def some_def
#value = TEST_VALUE # this will be enough to fetch the constants.
end
But, make sure you restart your server after changing the intializer.
You're looking to create a constant, which is basically a variable which doesn't change its value
You'd typically set these with initializers:
#config/initializers/your_initializer.rb
YOUR_CONSTANT = your_date
To maintain a persistent date, you'll have to give some more context on what you're using it for. It will be difficult to create this each time Rails loads (how to know which Time.now to use), so giving us more info will be a good help
You can also use an opposite approach. Assuming you should know the date when the new feature comes (for example 2014-04-04 18:00) you can just find a number of seconds left till the target date:
#seconds_left = Time.parse('2014-04-04 18:00').to_i - Time.now.to_i
then pass it to client side and implement a timer. So you'll just need to store a string representation of a target date.
Obvious disadvantage of this approach is that you should adjust that target time each time you want to introduce a new feature.

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