aboutsummaryrefslogtreecommitdiffstats
path: root/railties/doc/guides/source/actioncontroller_basics/session.txt
blob: 467cffbf85819454374efeb3ba8ed3f75cc74cd0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
== Session ==

Your application has a session for each user in which you can store small amounts of data that will be persisted between requests. The session is only available in the controller and can use one of a number of different storage mechanisms:

 * CookieStore - Stores everything on the client.
 * DRBStore - Stores the data on a DRb client.
 * MemCacheStore - Stores the data in MemCache.
 * ActiveRecordStore - Stores the data in a database using Active Record.

All session stores store the session id in a cookie - there is no other way of passing it to the server. Most stores also use this key to locate the session data on the server.

The default and recommended store, the Cookie Store, does not store session data on the server, but in the cookie itself. The data is cryptographically signed to make it tamper-proof, but it is not encrypted, so anyone with access to it can read its contents. It can only store about 4kB of data - much less than the others - but this is usually enough. Storing large amounts of data is discouraged no matter which session store your application uses. Expecially discouraged is storing complex objects (anything other than basic Ruby objects, the primary example being model instances) in the session, as the server might not be able to reassemble them between requests, which will result in an error. The Cookie Store has the added advantage that it does not require any setting up beforehand - Rails will generate a "secret key" which will be used to sign the cookie when you create the application.

If you need a different session storage mechanism, you can change it in the `config/environment.rb` file:

[source, ruby]
------------------------------------------
# Set to one of [:active_record_store, :drb_store, :mem_cache_store, :cookie_store]
config.action_controller.session_store = :active_record_store
------------------------------------------

=== Disabling the session ===

Sometimes you don't need a session, and you can turn it off to avoid the unnecessary overhead. To do this, use the link:http://api.rubyonrails.org/classes/ActionController/SessionManagement/ClassMethods.html#M000649[session] class method in your controller:

[source, ruby]
------------------------------------------
class ApplicationController < ActionController::Base
  session :off
end
------------------------------------------

You can also turn the session on or off for a single controller:

[source, ruby]
------------------------------------------
# The session is turned off by default in ApplicationController, but we
# want to turn it on for log in/out.
class LoginsController < ActionController::Base
  session :on
end
------------------------------------------

Or even a single action:

[source, ruby]
------------------------------------------
class ProductsController < ActionController::Base
  session :on, :only => [:create, :update]
end
------------------------------------------

=== Accessing the session ===

In your controller you can access the session through the `session` instance method.

NOTE: There are two `session` methods, the class and the instance method. The class method which is described above is used to turn the session on and off while the instance method described below is used to access session values. The class method is used outside of method definitions while the instance methods is used inside methods, in actions or filters.

Session values are stored using key/value pairs like a hash:

[source, ruby]
------------------------------------------
class ApplicationController < ActionController::Base

private

  # Finds the User with the ID stored in the session with the key :current_user_id
  # This is a common way to do user login in a Rails application; logging in sets the
  # session value and logging out removes it.
  def current_user
    @_current_user ||= session[:current_user_id] && User.find(session[:current_user_id])
  end

end
------------------------------------------

To store something in the session, just assign it to the key like a hash:

[source, ruby]
------------------------------------------
class LoginsController < ApplicationController

  # "Create" a login, aka "log the user in"
  def create
    if user = User.authenticate(params[:username, params[:password])
      # Save the user ID in the session so it can be used in subsequent requests
      session[:current_user_id] = user.id
      redirect_to root_url
    end
  end

end
------------------------------------------

To remove something from the session, assign that key to be `nil`:

[source, ruby]
------------------------------------------
class LoginsController < ApplicationController

  # "Delete" a login, aka "log the user out"
  def destroy
    # Remove the user id from the session
    session[:current_user_id] = nil
    redirect_to root_url
  end

end
------------------------------------------

To reset the entire session, use link:http://api.rubyonrails.org/classes/ActionController/Base.html#M000855[reset_session].

=== The flash ===

The flash is a special part of the session which is cleared with each request. This means that values stored there will only be available in the next request, which is useful for storing error messages etc. It is accessed in much the same way as the session, like a hash. Let's use the act of logging out as an example. The controller can set a message which will be displayed to the user on the next request:

[source, ruby]
------------------------------------------
class LoginsController < ApplicationController

  def destroy
    session[:current_user_id] = nil
    flash[:notice] = "You have successfully logged out"
    redirect_to root_url
  end

end
------------------------------------------

The `destroy` action redirects to the application's `root_url`, where the message will be displayed. Note that it's entirely up to the next action to decide what, if anything, it will do with what the previous action put in the flash. It's conventional to a display eventual errors or notices from the flash in the application's layout:

------------------------------------------
<html>
  <!-- <head/> -->
  <body>
    <% if flash[:notice] -%>
      <p class="notice"><%= flash[:notice] %></p>
    <% end -%>
    <% if flash[:error] -%>
      <p class="error"><%= flash[:error] %></p>
    <% end -%>
    <!-- more content -->
  </body>
</html>
------------------------------------------

This way, if an action sets an error or a notice message, the layout will display it automatically.

If you want a flash value to be carried over to another request, use the `keep` method:

[source, ruby]
------------------------------------------
class MainController < ApplicationController

  # Let's say this action corresponds to root_url, but you want all requests here to be redirected to
  # UsersController#index. If an action sets the flash and redirects here, the values would normally be
  # lost when another redirect happens, but you can use keep to make it persist for another request.
  def index
    flash.keep # Will persist all flash values. You can also use a key to keep only that value: flash.keep(:notice)
    redirect_to users_url
  end

end
------------------------------------------

==== flash.now ====

By default, adding values to the flash will make them available to the next request, but sometimes you may want to access those values in the same request. For example, if the `create` action fails to save a resource and you render the `new` template directly, that's not going to result in a new request, but you may still want to display a message using the flash. To do this, you can use `flash.now` in the same way you use the normal `flash`:

[source, ruby]
------------------------------------------
class ClientsController < ApplicationController

  def create
    @client = Client.new(params[:client])
    if @client.save
      # ...
    else
      flash.now[:error] = "Could not save client"
      render :action => "new"
    end
  end

end
------------------------------------------