A session object is created for each user in the Rails application, and the previous request information can be used continuously. Sessions are only available in Controller
and View
, and a small amount of data is stored in the session.
You can select the session storage destination from the following storages.
--ʻActionDispatch :: Session :: CookieStore: Save all sessions in the cookie of the client-side browser --ʻActionDispatch :: Session :: CacheStore
: Save data to Rails cache
--ʻActionDispatch :: Session :: ActiveRecordStore: Save to database using Active Record (requires activerecord-session_store gem) --ʻActionDispatch :: Session :: MemCacheStore
: Store data in memcached cluster (this implementation is old so you should consider CacheStore)
The session has a unique Id and stores it in a cookie
. Passing the session ID as ʻURLis very dangerous for security, so it is not allowed by default in
Rails. Therefore, the session ID must be passed as
cookie`.
Many SessionStore
s (session IDs) are used to retrieve session data on the server.
However, only CookieStore
stores all session data in cookie
itself (session ID can be used if necessary).
CookieStore
is used by default in Rails
and is the recommended session store in Rails
.
The advantage of CookieStore
is
--Very lightweight --No preparation is required for new use
The cookie
data is given an encrypted signature to prevent tampering, and the cookie itself is encrypted, so the content is read by others. (The tampered cookie
will be rejected by Rails
)
About 4KB of data can be stored in the CookieStore
, which is enough capacity. Regardless of the type of session store you use, it is not desirable to store large amounts of data in a session.
Consider ʻActionDispatch :: Session :: CacheStore` if the user session does not contain important data or if you do not need to store the session for a long time.
The merit is that the existing cache infrastructure can be used as it is because it is saved using the cache implementation set in the Web application. Therefore, no special preparation is required.
The disadvantage is that the session is short-lived and can disappear at any time.
Access to the session is made possible using the session
instance method in the controller. Session values are stored using hash-like key / value pairs.
class ApplicationController < ActionController::Base
private
#Search for users by id stored in a keyed session
# :current_user_id is a standard way to handle user logins in Rails applications.
#When you log in, the session value is set and
#The session value is deleted when you log out.
<Method ①>
def current_user
@current_user ||= session[:current_user_id] &&
User.find_by(id: session[:current_user_id])
end
<Method ②>
def current_user
if session[:current_user_id]
@current_user ||= User.find_by(id: session[:current_user_id])
end
end
end
If you want to save something in the session, assign a key like a hash.
class LoginsController < ApplicationController
# "Create" a login, aka "log the user in"
def create
if user = User.authenticate(params[:username], params[:password])
#Save the session user id and
#Make it available for future requests
session[:current_user_id] = user.id
redirect_to root_url
end
end
end
If you want to remove some of the data from the session, delete that key-value pair.
class LoginsController < ApplicationController
#Delete login(=Logout)
def destroy
#Remove user id from session id
session.delete(:current_user_id)
#Clear the current user memoized
@_current_user = nil
redirect_to root_url
end
end
Use reset_session to reset the entire session.
5-2. Flash
flash
is a special part of the session that is cleared on every request. It has a feature that it can be referenced only immediately after the request, and an error message is passed to view
.
The flash
is accessed as a hash and is called a FlashHash
instance.
As an example, let's deal with the operation of logging out. By using flash in the controller, you can send the message to be displayed in the next request.
class LoginsController < ApplicationController
def destroy
session.delete(:current_user_id)
flash[:notice] = "You have successfully logged out."
redirect_to root_url
end
end
The flash
message can also be assigned as part of a redirect. In addition to : notice
and: alert
as options, general : flash
can also be used.
redirect_to root_url, notice: "You have successfully logged out."
redirect_to root_url, alert: "You're stuck here!"
redirect_to root_url, flash: { referral_code: 1234 }
cookie
on the client side (browser). Since HTTP
is a" stateless "protocol, there is basically no association between requests, but with cookie
you can use it between requests (or even between sessions). ) This data will be retained. In Rails
, you can easily access cookies
using the cookies
method. The access method is very similar to that of a session, acting like a hash.class CommentsController < ApplicationController
def new
#If the comment author name remains in the cookie, it will be automatically entered in the field
@comment = Comment.new(author: cookies[:commenter_name])
end
def create
@comment = Comment.new(params[:comment])
if @comment.save
flash[:notice] = "Thanks for your comment!"
if params[:remember_name]
#Comment Save the author name
cookies[:commenter_name] = @comment.author
else
#Comment Delete the author name if it remains in the cookie
cookies.delete(:commenter_name)
end
redirect_to @comment.article
else
render action: "new"
end
end
end
When deleting a session, it was deleted by specifying nil
as the key, but when deleting cookies
, you must use cookies.delete (: key)
instead of this method.
Rails
can also use a signed cookie jar
and an encrypted cookie jar
to store sensitive data.
--Signed cookie jar
prevents tampering with cookie
by adding an encrypted signature to the cookie
value.
--Encryption cookie jar
adds a signature and encrypts the value itself so that it cannot be read by the end user.
These special cookie
s use a serializer to convert the value to a string, save it, and do a deverse conversion (deserialize
) on read to return it to a Ruby
object.
Rails.application.config.action_dispatch.cookies_serializer = :json
The default serializer for new applications is : json
.
It is recommended to store only "simple data" such as strings and numbers in cookie
. If you have to store a complex object in cookie
, you have to take care of the conversion when reading the value from cookie
in a subsequent request.
The same is true for session
and flash
hashes when using the cookie
session store.
Thanks to ʻActionController, it is very easy to output (render)
XMLdata and
JSONdata. The controller generated using
scaffold` is as follows.
class UsersController < ApplicationController
def index
@users = User.all
respond_to do |format|
format.html # index.html.erb
format.xml { render xml: @users }
format.json { render json: @users }
end
end
end
Note that in the code above, it's render xml: @users
instead of render xml: @ users.to_xml
. Rails
will automatically call to_xml
if the object is not of type String
.
.to_xml
A method that converts an array or hash to XML format.
array.to_xml([option])
hassh.to_xml([option])
A filter is a method that is executed "before", "after", or "both immediately before" and "around" an action in the controller.
The filter is inherited, so if you set the filter in ApplicationController, the filter will be enabled in all controllers of the application.
A common use of "before" filters is to require a user to log in before performing an action. This filter method looks like this:
class ApplicationController < ActionController::Base
before_action :require_login
private
def require_login
unless logged_in?
flash[:error] = "You must be logged in to access this section"
redirect_to new_login_url # halts request cycle
end
end
end
This method is as simple as saving the error message in flash
and redirecting to the login form if the user is not logged in.
In this example, we added a filter to ʻApplicationController, so all controllers that inherit it will be affected. This means that you will be required to log in for every feature of your application. Of course, if you request authentication on every screen of the application, you will not be able to display the login screen required for authentication, so set the login request on all controllers and actions like this. Should not be. The
skip_before_action` method allows you to skip a filter for a particular action.
class LoginsController < ApplicationController
skip_before_action :require_login, only: [:new, :create]
end
By doing the above, the new
and create
actions of LoginsController
can still be authenticated-free. You can use the : only
option if you want to skip the filter only for a particular action. Conversely, if you don't want to skip the filter only for a particular action, use the : except
option. These options are also available when adding filters, so you can add filters that only run for the action you select in the first place.
filter and ʻaround
filterIn addition to the "before" filter, you can also use a filter that is executed after the action is executed, or a filter that is executed both before and after the action is executed.
The "after" filter is similar to the "before" filter, but in the case of the "after" filter, the action has already been executed and the response data that is about to be sent to the client can be accessed. Different from filters. Of course, no matter how you write the "after" filter, the execution of the action will not be interrupted. However, please note that the "after" filter is executed only after the action is successful, and is not executed if an exception occurs in the middle of the request cycle.
If you use an "around" filter, you are obliged to do a yield
somewhere in the filter to perform the associated action. This is similar to how Rack middleware works.
For example, consider a website that has an approval workflow for any changes. Administrators can easily preview these changes and approve them within a transaction.
class ChangesController < ApplicationController
around_action :wrap_in_transaction, only: :show
private
def wrap_in_transaction
ActiveRecord::Base.transaction do
begin
yield
ensure
raise ActiveRecord::Rollback
end
end
end
end
Note that for "around" filters, screen output (rendering) is also included in the work. Especially in the above example, if the view itself reads from the database (using scope etc.), the read will be done within a transaction and the data will be displayed in the preview.
You can also build your own response without running yield
. In this case, no action is taken.
Recommended Posts