Birds-Eye.Net
All things broadband and more...
 
Web Birds-Eye.Net

What's New?

Ruby on Rails (RoR)
Programming Reference


Models
External database connections
Passing current_user into model
Passing object into model
Using static lookup tables
Validates IF
Validates MongoMapper

Views
Dynamically delete form element
Edit create nested data
HTML form field check_box
Layout jQuery datatable module
Select array
Select cascading via JS
Text_area Array
Text_area listing submit
Text field format time

Controllers
Dynamic model selection
Including first item from a sorted desc table
Using from_unixtime on epoch dates

Rack
Integrated NTLM/Kerberos Authentication
Pass-through Authentication w/ NTLM

ActionMailer
Broken links in emails

Rails General
Add, Subtract, Multiply, and Divide
Calculate number of weekdays for date range
Date->Epoch & Epoch->Date
Extract first letter of each word
Hash of hashes assignment
Using: variable as hash index

jQuery
jQuery accordion MongoDB


More to come

 

Passing current_user into Model using Virtual Attributes

By: Bruce Bahlmann - Contributing Author (your feedback is important to us!)

In rails development, you may run up against a known limitation in Rails that prevents access to data defined elsewhere (for example in the application controller) from within a model. It is a common problem that within a given model, you would want access to such data. Information represented by current_user in particular is very useful to have in the model. As developer you have several options for accessing such data. One way is through the use of the "cattr_accessor" which provides classes with read/write attributes, however since these attributes are at the class level, simultaneous interactive web sessions overwrite these so this solution has its limitations. Another solution would be to use threads and I have read some websites that make this option somewhat compelling, however threads are not completely safe from simultaneous sessions either and also open a can of worms that forces the developer to be mindful of the application server and web server they are using which quickly expands the scope of the problem. One could also venture down the road of using subclasses - but while that may be a more elegant solution, lets just say at this point we are well beyond simple solution to a very simple problem. But having experienced this myself, I'm amazed by the general lack of documentation out there.

Fortunately, Ruby on Rails (RoR) provides an easy way to do this that you don't have to worry about problems with simultaneous interactive sessions or what you are using for an application server or web server. What I believe is the easiest way to provide current_user information within models is to use virtual attributes. Here is how it works:

[app/models/inventory.rb]
class Inventory < ActiveRecord::Base
 attr_accessor :cUser
...
First you define a virtual attribute within your model. Note, you do not need to create a method for it, just simply define it as above. It is a good idea not to define the virtual attribute as current_user if that is how it used elsewhere. So, I just create a shorthand name for use in this model. You can name it what ever you want, just be consistent with how you define it and use it between the controller and the model.

Keep in mind, that virtual attributes are just that - virtual. While you may attach or associate them with objects whose contents may be committed to a database, the virtual attributes will NOT be committed. Virtual attributes do not pertain to columns in a database.

[app/controllers/inventory.rb]
...

 # POST /inventories
 # POST /inventories.json
 def create 
   @inventory = Inventory.new(params[:inventory])

   ## Send model virtual attributes (these are not committed to the database - simply used to log activity
   @inventory.cUser = @current_user.name
...

 # PUT /inventories/1
 # PUT /inventories/1.json
 def update
   @inventory = Inventory.find(params[:id])

   ## Send model virtual attributes (these are not committed to the database - simply used to log activity
   params[:inventory]["cUser"] = @current_user.name
...

Now that the virtual attribute is defined, we need to give this attribute a value some place where the value is available (like in the controller). There are two areas within the controller that we want to populate cUser - create and update. Both actions involve processing form information submitted by the user. The objective here is to assign cUser a value just prior to it being handed to a model where verification and saving happen - this prevents simultaneous interactive sessions from overwriting this value.

[app/models/inventory.rb]
class Inventory < ActiveRecord::Base
 attr_accessor :cUser
...

 validate :custom_validation

 def custom_validation
 
  if errors.count > 0
    ## Any post processing of errors prior to returning back to edit/new page

  else 
    ## Any post processing when NO errors are found (prior to saving)
    time = Time.now.to_i
    self.notes = "#{time}|#{cUser}|Inventory first entered"
  end
...

Finally, back in the model, we can now work with the value we assigned cUser in the controller with confidence that the value of cUser will not be overwritten. In our case, we are using the cUser within a custom validation method where if no errors are found, we want to append a message to the log (e.g. notes) that includes the user currently logged in who is making the change.

See Also: Passing Object into Model using Virtual Attributes

Can Birds-Eye.Net help you or your Company?
Receive your Birds-Eye.Net articles and white papers hot off the presses by adding our RSS feed to your reader.

 

 

(C) Copyright Birds-Eye.Net, All rights reserved.
It is against the law to reproduce this content or any portion of it in any form without the explicit written permission of Birds-Eye Network Services, LLC. Federal copyright law (17 USC 504) makes it illegal, punishable with fines up to $100,000 per violation plus attorney's fees.