Rails: controller, view and helper life cycles - ruby-on-rails

I wonder if there is any doc on that. I believe it is helpful to know when those objects get created and destroyed and whether they are re-used (like Java servlets). Particularly, I am wondering about helpers. I assume a new controller instance is created for every new request, and the same is true for views but not for helpers. In his tutorial Michael Hartl uses SessionsHelper to store the current user, which makes me think helper lifetime is bound to the session. Is this correct? Then technically I can use helpers to store session info, right?

The basic flow goes like this:
(request) -- Rack stuff -- Controller instance -- View instance -- (response)
Any instance variables you set in the Controller are made available to the View. Those are threadsafe. Class variables, on the other hand, are not threadsafe.
Helpers are Modules, not Classes, so they aren't (can't be, really) instantiated. Instead, they're mixed into the View instance that evaluates your templates. Again, instance variables are threadsafe, class variables aren't.

My thinking is that helper methods, as with every other part of a Rails app, is created & destroyed with each request
You have to remember the helper methods will not "store" any session data - they'll only call the session cookies to display the relevant data:
Most applications need to keep track of certain state of a particular
user. This could be the contents of a shopping basket or the user id
of the currently logged in user. Without the idea of sessions, the
user would have to identify, and probably authenticate, on every
request. Rails will create a new session automatically if a new user
accesses the application. It will load an existing session if the user
has already used the application.
A session usually consists of a hash of values and a session id,
usually a 32-character string, to identify the hash. Every cookie sent
to the client's browser includes the session id. And the other way
round: the browser will send it to the server on every request from
the client. In Rails you can save and retrieve values using the
session method:
This demonstrates, to me at least, that every time you load a "helper", it's really relying on the user's stored data (particularly for the session). This means that although it may appear that a helper's lifecycle may extend beyond each request, it's really just relying on the data provided
Having said that, I need to read up on how to make this threadsafe etc, as per benjamin sinclaire's comment

Related

rails 4- where to put user function

I am building a sample app for learning rails 4, and I'm a little confused on where I'm meant to build certain things. For example, I want to check if a user is logged in, and if so, display their account balance in the header (a partial).
Thanks to Michael Hartl's tutorial, I have a function to check a user's login status in the session helper, which is included in the application controller and can therefore be accessed in the partial.
Since the balance is tracked in the Users table, do I build a function get_balance in the Users model? Or should I create a function in the application helper? If I do build it in the application helper, is this auto-included in the application controller, or do I have to include it specifically? If I don't build the function in the model, can I still access the User object?
Thanks for your patience with a noob.
Since your users balance is a column in Users table, it is already there for you as a field (most possibly user.balance). And yes, this is where you should store it. You might use helpers for stuff that is related to general layout of your application and use combination of partial view and layout to spread it around.
Since it's already on your table, assuming your user is logged in, you could just call
current_user.balance
But it sounds like you want to add onto the data given,
I would suggest perhaps using a Rails decorator for your user model.
Basically a decorator adds an object-oriented layer of presentation logic to your Rails application.
I use the Draper Gem

rails mvc helper class for calling outside data (Viddler)

I've got an app that is using Viddler's API and the viddler-ruby gem. Originally there was only one spot in the app that was going to authenticate and request video information, but there's been a change and I might need to do it in a few places.
I could do it as a method in application_helper but then whenever that method would be called it would authenticate and perform a function (and as I'm thinking about it, there could be more than one function needed).
So I'm thinking a class upon instantiation, authenticates, keeps that authenticated #viddler object and has public methods that can be called on the class (ie ViddlerMaster.getImage(video)) -- my question is is this a controller or a model? In my thinking it's dealing with data so it'll be a model, one that doesn't connect to the database in any way; is my thinking correct, or is there A Better Way?

Keep value in memory across requests and across users in Rails controller? Use class variable?

We're on Rails 3.0.6.
We maintain a list of numbers that changes only once a month, but nearly every page request requires access to this list.
We store the list in the database.
Instead of hitting the database on every request and grabbing the list, we would like to grab the data once and stash it in memory for efficient access.
If we store the list in each user session, we still need to hit the database for each session.
Is there a way to only hit the database once and let the values persist in memory across all users and all sessions? We need access to the list from the controller. Should we define a class variable in the controller?
Thanks!
I think Rails.cache is the answer to your problem here. It's a simple interface with multiple backends, the default stores the cache in memory, but if you're already using Memcached, Redis or similar in your app you can plug it into those instead.
Try throwing something similar to this in your ApplicationController
def list_of_numbers
#list_of_numbers ||= Rails.cache.fetch(:list_of_numbers, :expires_in => 24.hours) do
# Read from database
end
end
It will try to read from the cache, but if it doesn't find it, will do the intensive stuff and store it for next time
The pattern you're looking for is known as a singleton which is a simple way to cache stuff that doesn't change over time, for example, you'll often see something like this in application_controller.rb -- your code always calls the method
def current_user(user_id)
#current_user ||= User.find user_id
end
When it does, it checks the instance variable #current_user and returns it if not nil, otherwise it does the database lookup and assigns the result to the instance variable, which it returns.
Your problem is similar, but broader, since it applies to all instances.
One solution is with a class variable, which is documented here http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_classes.html#S3 -- a similar solution to the one above applies here.
This might be a good solution in your case, but has some issues. In specific, (assuming this is a web app) depending on your configuration, you may have multiple instances of Rails loaded in different processes, and class variables only apply to their specific instance. The popular Passenger module (for Apache and Nginx) can be configured to allow class variables to be accessible to all of it's instances ... which works great if you have only one server.
But when you have multiple servers, things get a little tricky. Sure, you could use a class variable and accept that you'll have to make one hit to the database for each server. This works great except for the when that the variable ... varies! You'll need some way of invalidating the variable across all servers. Depending on how critical the it is, this could create various very gnarly and difficult to track down errors (I learned the hard way :-).
Enter memcached. This is a wonderful tool that is a general purpose caching tool. It's very lightweight, and very, very smart. In particular, it can create distributed caches across a cluster of servers -- the value is only ever stored once (thus avoiding the synchronization problem noted above) and each server knows which server to look on to find any given cache key. It even handles when servers go down and all sorts of other unpleasantries.
Setup is remarkably easy, and Rails almost assumes you'll use it for your various caching needs, and the Rails gem just makes it as simple as pie.
On the assumption that there will be other opportunities to cache stuff that might not be as simple as a value you can store in a class variable, that's probably the first place to start.

How do you access the session from within an ActionMailer class?

I have is an application can be accessed from 2 different URLs and looks/behaves slightly different depending on which URL you use to access it. I'm able to do this by storing a value in the session object and basing some decisions off of it such as which path views get loaded from.
This sort of approach seemed like it would work until I needed to have different URL's sent out in emails. In a class that inherits from ActionMailer, I need to set the default_url_options[:host] based on the value of a session variable. Rails throws the following error when I call session from anywhere within the mailer:
undefined local variable or method `session' for ApplicationMailer:Class
The less-than-desirable way to handle this is to pass the session variable into my mailer calls. I'd rather not do this as it doesn't seem very DRY and would require changes to much of my code.
Whether you can shoehorn a reference to the session into the mailer or not, I think you've already hit upon the correct solution. Passing in the context you want to use would be preferable for a couple of reasons.
The mailer probably shouldn't know about the session in the first place.
Assume that someday you have to send a lot of mail, and batch process it. You'll be right back to where you are now -- having to pass in your context.

Ruby on Rails MVC Question

I intend to store in a database a minimal amount of information pertaining to a book (title, isbn). However, on display I'd like to display additional attributes (pages, author, cover image) not stored in the database. I plan on getting this information from the Amazon Web Services (AWS) using Ruby/AWS. I am very new to Ruby on Rails and am not sure exactly how this would/should be performed.
Some options that spring to mind include modifying the books controller or creating an entirely separate model based on the Amazon entities that relies upon searching for books listed only in my database.
Your ActiveRecord book model can be customized to retrieve the additional attributes from AWS. Your view and controllers will be clueless and DRY.
When you ever need to deal with any data, in any MVC environment, it needs to go in the model. You could create an additional other_information method that uses ||= to either get the other information from AWS or returns the information from an instance variable. Either that or you could create a find_with_info method that gets it all at the same time :)
But defiantly keep any data-related tasks in the model.
I would suggest creating methods in the model. Are you always going to be pulling the extra info every time you show these entries? If not you will want to maybe have a different controller action for either the "extended" (ie with amazon info) or "limited" (ie without the amazon info) and have the other be the standard. This way you can pull exactly what you want when you want it and make sure you hit amazon only when you need to, not with every single show or index call.

Resources