Is this an ok design decision? is there a better way? - ruby-on-rails

So, For the sake of performance, I'm using database sessions. I figure that while the sessions are server side, I might as well store commonly accessed objects in the session. So, I'm storing serialized versions of the current_user, current_account, and the current_user's permissions.
The User model handels a lot of the permissions methods (things like user.can_do_whatever), but since i'm trying to be more efficient, and store commonly accessed things in the session (this allows for far fewer DB accesses), does it make sense / break any design standards to (upon each request) store the session in an instance variable in the current_user ?
As of right now, I can't think of any alternatives.

ROR application have by default a RESTful design. One rules of REST is stateless. that mean each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server.
If you have trouble with Database performance, use a cache system like memcached wich is already integrated in rails (Caching with Rails).

I found a couple of references warning against storing non-primitive data types in the session, but they were all just warnings, and boiled down to: Storing complex objects is "Expecially discouraged" [sic], but if you decide you need to... well, just be careful.
Anyway, I'm kinda taken by the idea of having the users table double as the sessions table, but serialization still seems a bit sketchy. If you're just trying to cut down the number of DB requests, what about storing IDs and using :joins when looking up your user (might require a bit of hackery to get that worked into the default session loading). That avoids synchronization problems and serialization sketchiness, and still only generates a single DB query. Just make sure to use :joins and not :include, as the latter generates a query for each table.
Hope that helps!

Related

What is the accepted method for a global state?

I was wondering what would you guys consider the best way to go about having some simple stuff stored across sessions without using the DB.
I'm looking to have like having 'modes' to a website. So it can be in mode a or b, and depending on the mode, buttons would do different things.
Would using Rails.cache.read and write be the best option ? I've heard it has issues with heroku if you leave the cache as filesystem, then has problems as a memcache because of multi-threading ?
I'm really trying to avoid having a whole table on DB getting used for users checking a global state of the site each request.
In order to have a "global" state, then you need to create a singke dependency for each instance of your application.
In fact, you can't rely on cookies or sessions, are they are client-oriented and they are not shared between clients.
The database is the most common approach. You may be able to use the file system in some cases, but not for Heroku as there may be several different instances of your app running under different file systems.
Any solution that can easily be shared across instances will work:
Memory database like Redis
SQL or NoSQL database
Cache systems, as long as they are not specific to one instance. Memcached may work, but it's not persistent (hence you may lose the state)
External storage (such as Amazon S3)
To me, a relational database or a memory database such as Redis seems to be the most plausible solution.
If you want per-user setting - consider storing in session (which can be stored in cookies), or directly in cookies.
Both methods end up storing some data (but not lots of it, because cookies are passed by browser with each request) inside clients' browsers.
You could put it in a table - just so that you have it, but then make the value available via the ApplicationContoller, with a simple cache method in between
so something like: - not tested!!
def get_mode
if #mode_timeout.nil? or #mode_timeout < Time.now
#mode = ModeModel.first.mode
#mode_timeout = Time.now + 60.seconds
end
#mode
end
You'll have to create a model, or you could update if via a controller with a set_mode method instead, but that would be more transient.
Then you can just call get_mode from your controller.

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.

Rails security concerns

I am a Java programmer mostly, and it's actually amazing that we don't have to worry about a lot of security concerns that php or even rails developers have to worry about. We have to worry about them, but I think our job is actually a lot easier. You just use Java (already big bonus points there) and use Spring with Spring security... and you're basically done. Java and servlets are actually really good in this respect.
Now that I'm working in Rails, I think the biggest security concerns that I am the most scared of are parameters - both in the ones that are coming from the controllers (since they dynamic hashes, unlike in SpringMVC) and having to include more hidden values in forms.
But that got me thinking - you really have to be careful what you accept when you create new models or even update models. If you just blindly pass in parameters to your models, bad things can happen. In fact, things like the user role and stuff could be changed if you're not too careful.
It's almost like I want to write the setter code by hand to make sure it's not overwriting something that it shouldn't. And even if there's a framework mechanism to handle this... I would still want to test every risky model attribute just to be extra sure that it won't get overwritten on a create and on an update.
As much as Java gets a bad rep about productivity, it feels like it handles this stuff a lot better.
Anyway, my question is - what is the best resource/tips/advice for dealing with common security pitfalls/concerns/gotchas using rails - especially geared towards a Java/Spring developer who got used to working in a more stateful environment.
Even better, what would be a good checklist to go through every once in awhile?
And last, what tests would you recommend to make sure things are solid?
At least for your concern about assigning data to your model objects without proper checking, look into the attr_accessible declaration; it allows only specified attributes to be assigned via the bulk assignment:
user = User.new(params[:user])
user.approved = params[:user][:approved]
user.role = params[:user][:role]
You might find the entire 27th chapter of the Ruby on Rails 3rd edition book useful. (I haven't updated my 4th Edition book yet, not sure which chapter to recommend from the newer book. :)
I don't use ActiveRecord (I use DataMapper), but as a rule, I never do mass-assignment and I always expressly pass only the attributes I want to change. Rails 3 defaults to escaping all content in your views, unless you expressly output that data raw into into the .erb.
Also, it really bugs me that ActiveRecord doesn't help you out very much if you need to drop down to using SQL for something. You have to escape input yourself, which can expose you to the risk of human error allowing arbitrary SQL to be executed in your queries. DataMapper's underlying DataObjects connection supports prepared statements out of the box and in fact, it would actually require more work to avoid using them.
Rails 3 does have CSRF protection turn on by default too. It also makes session cookies HTTP-only by default, which makes them harder to steal via JavaScript.
I actually think, aside from Rails encouraging the use of mass-assignment, you're pretty well-covered for security.

Persistent resources in a rails app

First, this may not be the best title, but it seems to make sense at this time.
What I'm looking at is loading a resource which should live for the life of the web app. There may be some provisioning at a later point for a manual refresh, but currently that is not the case.
We have a complex permission structure which resides in the database for multiple reasons. I do not want to incur the overhead of retrieving this for each page load, thus I want it to reside in memory. My first instinct is to create a singleton which I load this into and use it whenever needed to lookup a permission. I understand the hesitance towards singletons and wonder if that is a poor approach.
I do not want to go down the route of yaml or another storage mechanism, the permissions must reside in the DB for other dependencies. That said, in Rails, what would be the most appropriate way to efficiently load and read the data?
This sounds like the perfect use of the cache
permissions = Rails.cache.fetch( 'permissions' ) do
# Permissions don't exist yet, perform long operation and load from DB
load_permissions_from_db
end
More details here.
I'm not totally sure what you mean but i think there are a few ways you could go
caching (e.g. caches_page :page or caches_action :action in the controller )
or possibly storing something in a cookie/ session data, of course i don't totally understand the nature of this data so I don't Know what would work better, if at all

How should I go about using a rdbms and mongodb in a rails app?

I'm currently testing the waters with mongoid and have so far begun on an ecommerce store. Now of course mongoid doesn't have transactions so I'd like to ideally use mongoid for most of the app including authentication, authorization, product information etc.
However, the lack of transactions necessitate a return to an rdbms. The rdbms would be used purely to record financial transactions.
Is this possible in rails and has anyone done it?
I have limited experience with rails in general but I imagine having the secure part mounted as a engine and urls scoped under secure.myapp.com or myapp.com/secure/ and the user would be redirected to the ssl while rack takes care of things like shared sessions.
Would this work? Or has anyone found a better way of implementing this?
It is possible to mix mongoDB and a traditional RDMS, but you may have to do some extra coding on your part if you want ActiveRecord objects to communicate with MongoDB objects, since the ORMs are different. Keep in mind that while it is true that MongoDB does not support transactions across multiple documents, it does support 'transactional' atomic updates - which means that if all the data you are updating is contained within a single document you don't have to worry about transactions. MongoDB also supports safe updates, allowing you to verify that data has been written to n different replica servers and has been persisted to disk.
As for shared sessions between HTTPS and HTTP - this is not something you have to worry about. You'll define your session store as either MongoDB, MySQL, Memcached or, my recommendation, Cookies. As long as you define your domain as '.myapp.com' the cookies will be shared across all subdomains of your application regardless of the protocol.
While I can't comment directly on the rails aspect of the question, as with the first poster's response, MongoDB does support transactional updates. It's probably simpler to implement your entire system in Mongo, or in an RDBMS.
The real question is what is the motivation behind using mongo here? What are you hoping to gain from a document database model? Do you just want to rip RoR objects directly to mongo?
Just a suggestion, (abstractly) but you could just strictly define your objects up front, and represent that definition in your RDBMS. It will probably save you a lot of time if you don't have a clear motivation for using Mongo. Mongo is an awesome technology, but it's best for sorting through data and cataloging data, rather representing strict data structures (not that it's incapable of doing so, necessarily, but with a document database, you have a lot more flexibility with the content of each object within your db).
Good luck!

Resources