Rails 3 - constructor action in controller? - ruby-on-rails-3

I need to store a value from the database in a variable, and I need to access this variable from all the actions in my controller.
For example, I have the controller home which has 3 actions:
about
contact
blog
I tried to store the value to a variable in application_controller.rb, but this did not work.
How can I do this?

This is about persistence. To get around the fact website are stateless you persist data by storing it in a cookie. Rails gives you a convenient way of doing this called a session hash.
You can also use the flash hash (This is also a session hash)
At the point where you get the value that you wish to store simply call
session[:some_variable] = some_variable
Then when you want to retrieve that variable just call
some_variable = session[:some_variable]
Replace some_variable with a something that makes sense to you
If you want to do this for all controller actions then a before_filter can be useful
Read here about before_filters http://apidock.com/rails/ActionController/Filters/ClassMethods/before_filter
Do not store large objects or arrays of objects in the session. If you need to keep a reference to an active_record object then store just the ID of the record then you can retrieve that record with a find when you need it

If you want to access to a specific variable in all your controller, just do the following.
Into the application controller :
before_filter :set_my_variables
private
def set_my_variables
#variable = MyModel.find(YOUR_CONDITION)
end
And for instance, in your home controller, you will be able to access to #variable.
Hope this helps.

Related

Keeping track of user ID with custom authentication

I am currently making an app on apex.oracle.com, and I've been trying to solve this for a couple hours now, but I have no idea how to.
Alright, so basically my application has custom authentication based on a user table I created inside of my application. Therefore, it seems to render useless most APEX_UTIL functions to retrieve info on the current user. The issue is, I am trying to find a way to store the user's numeric ID from my table in the session, so I could retrieve it directly in the queries throughout my application, in order to do something like WHERE id = :MEMBER_ID instead of WHERE UPPER(username) = UPPER(:APP_USER).
Now, the way I attempted to do this is by creating a Post Authentication procedure that retrieves the user ID based on the username, and stores that value in the session using APEX_UTIL.SET_SESSION_STATE( p_name => 'MEMBER_ID', p_value => member_id ). However, it seems that SET_SESSION_STATE is unable to create custom session values or something, returning an ERR-1002 every time I use a value name that isn't specifically mentioned in the documentation.
I am a total newbie to APEX so I am probably unaware of something, however I have done many searches, but I could not find anything specifically related to my issue.
Thanks a lot if you can help.
You're trying to store a value into an item, whether page or application level. This requires that the item with that name exists in one of those scopes. So, do you have an item somewhere that is called MEMBER_ID?
I'd suggest you create one in the application scope. Go through Shared Components > Application items. Once created, you should be able to assign a value either through apex_util.set_session_state or with bind variable syntax eg :MEMBER_ID := somevariable;
There are a number of ways you can do this. Some have already been suggested in other answers.
Application Item (as per Tom's answer)
PL/SQL package global (as per hol's answer) - although you'd have to reset it for each call (e.g. by adding code to the application's Security Attribute Initialization PL/SQL Code and clearing it by adding code to Cleanup PL/SQL Code).
Globally Accessible Context - this method, while a little more complex, has some benefits especially for security and debugging. I've described it here: http://jeffkemponoracle.com/2013/02/28/apex-and-application-contexts/, but basically:
Create a globally accessible context:
CREATE OR REPLACE CONTEXT MY_CONTEXT USING MY_PACKAGE ACCESSED GLOBALLY;
In the post-authentication procedure (in the database package MY_PACKAGE), you can store the data you wish to keep track of, e.g.
DBMS_SESSION.set_context
(namespace => 'MY_CONTEXT'
,attribute => 'MEMBER_ID'
,value => '12345whatever'
,client_id => v('APP_USER') || ':' || v('APP_SESSION'));
(note the caveats in my blog article and the subsequent comments from others about CLIENT_IDENTIFIER not being reliably set at the post-auth stage)
In your views, code, etc. you can access the MEMBER_ID by simply referring to SYS_CONTEXT('MY_CONTEXT','MEMBER_ID').

Sending more data to changeIdentity in CWebUser by overriding it?

Disclaimer: Complete beginner in Yii, Some experience in php.
In Yii, Is it OK to override the login method of CWebUser?
The reason i want to do this is because the comments in the source code stated that the changeIdentity method can be overridden by child classes but because i want to send more parameters to this method i was thinking of overriding the login method too (of CWebUser).
Also if that isn't such a good idea how do you send the extra parameters into the changeIdentity method.(By retrieving it from the $states argument somehow ??). The extra parameters are newly defined properties of UserIdentity class.
It is better to first try to do what you wish to do by overriding components/UserIdentity.php's authenticate method. In fact, that is necessary to implement any security system more advanced than the default demo and admin logins it starts you with.
In that method, you can use
$this->setState('myVar', 5);
and then access that anywhere in the web app like so:
Yii::app()->user->getState('myVar');
If myVar is not defined, that method will return null by default. Otherwise it will return whatever it was stored as, in my example, 5. These values are stored in the $_SESSION variable, so they persist as long as the session does.
UPDATE: Okay, took the time to learn how this whole mess works in Yii for another answer, so I'm sharing my findings here as well. The below is mostly copy pasted from a similar answer I just gave elsewhere. This is tested as working and persisting from page to page on my system.
You need to extend the CWebUser class to achieve the results you want.
class WebUser extends CWebUser{
protected $_myVar = 'myvar_default';
public function getMyVar(){
$myVar = Yii::app()->user->getState('myVar');
return (null!==$myVar)?$myVar:$this->_myVar;
}
public function setMyVar($value){
Yii::app()->user->setState('myVar', $value);
}
}
You can then assign and recall the myVar attribute by using Yii::app()->user->myVar.
Place the above class in components/WebUser.php, or anywhere that it will be loaded or autoloaded.
Change your config file to use your new WebUser class and you should be all set.
'components'=>
'user'=>array(
'class'=>'WebUser',
),
...
),

update_attributes rails differentiate between create and update

I have a nested form (very similar to the one shown in RailsCasts) that I use an update_attributes, which updates the parent object as well as updating and creating new child objects. I want to be able to differentiate between when a child object is created and when a child object is updated and when the parent object is updated. Is there anyway to do so? My immediate goal is to push a broadcast when a new child object is created.
Trying to use an after_create do in the child model doesn't work for my purpose because I'm trying to call an action in the application_controller.rb.
The code is my parent object controller is
if #parent_object.update_attributes(params[:parent_object])
...want the push_broadcast to go here if it's a new record.
If I use debugger, params[:parent_object] returns this
{"overall_sharing"=>"1", "permissions_attributes"=>{"0"=>{"id"=>"66"}, "1"=> {"can_edit"=>"1", "can_copy"=>"1", "_destroy"=>"false", "id"=>"74"}, "1341967403169"=>{"user_id"=>"171", "can_edit"=>"1", "can_copy"=>"1", "_destroy"=>"false", "note_id"=>"423"}}}
for reference, the last bit is the new child object, the first is updating the parent object and the middle is updating the child objects.
I don't know if the correct path is the try to mess with the params or to think of a different route. Any advice would be much appreciated.
Thanks, Welles
If it's a new record it won't have an id. Unlike when editing or updating.
Just try to find it. If you can't then it's new.
if params[:id]
#existing record
else
#new record
end
Rails api has a nice documentation for nested attributes. (Rails guide falls short in this regard, in my opinion). I think it should answer most of your questions.

Sencha Touch Issue with Stores

I have a store defined that I want to manually add data to. The store is connected to a model with the proper fields defined and the store is instantiated.
Why does this work
Ext.getStore('Inspections').add({"code":"123","descr":"Inspection 123"});
Why does this not work
Ext.getStore('Inspections').loadData([{"code":"123","descr":"Inspection 123"}]);
I get LoadData not defined error.
Because loadData is not a method on Store: http://docs.sencha.com/touch/2-0/#!/api/Ext.data.Store
What you want is setData.

Call recent posts on the layout

Imagine i have a blog, and i want a footer or sidebar displaying my 3 most recent posts at any given time.
What is the best way to do this?
I can call #recent_posts in every single controller to have them ready for the layout but this doesn't seem like the best way...at all...
#recent_posts = Posts.all(:limit => 3)
I've been fiddling around with partials, but they do need an instance variable carrying the #recent_posts.
There may be two parts to your concern: 1) performance, and 2) effort required. Both are easily addressed.
As Andrei S notes in his answer, the convenience/effort issue is mitigated by using a before_filter that calls the method that does the work from the ApplicationController class.
The performance issue is only slightly more work. Instead of the method being
def most_recent_posts
Posts.order(created_at DESC).limit(3)
end
instead do this
def most_recent_posts
#most_recent_posts ||= Posts.order(created_at DESC).limit(3)
end
which checks the instance variable for nil; if nil, it does the query and assigns the result to the instance variable.
You'll also need a way to update when a new post is added, so perhaps something like
def clear_most_recent_posts!
#most_recent_posts = nil
end
and then just call clear_most_recent_posts! from the method(s) that modify the table. The before_filter will do its work only when needed.
I am sure some more eloquent rubyist has a nicer way of doing this, but this is an idea.
You could put the part where you have your posts in a partial and use it in the general layout of your app.
To load them all in every controller you could do a before_filter in your ApplicationController in which you set your instance variable, which will be available in your partial that gets rendered in the layout
This way you only get to do it once, and it will get done everywhere (of course you could set conditions on the filter and the layout to load them when you need, that's if you don't really need them on every page)