##0. Mass Assignment
-
Mass assignment allows us to set a bunch of attributes at once:
attrs = { :first => "John", :last => "Doe", :email => "[email protected]"} user = User.new(attrs) # Without the convenience of mass assignment, # we'd have to write an assignment statement for each attribute # to achieve the same result. user.first = attrs[:first] user.last = attrs[:last] user.email = attrs[:email]
http://code.tutsplus.com/tutorials/mass-assignment-rails-and-you--net-31695
##1. GET and POST
-
GET
request parse data by query string which is appended to the URL. The length of query string is limited to 2048 characters. And all chars must be ASCII code chars.foo://example.com:8042/over/there?name=ferret#nose \_/ \______________/\_________/ \_________/ \__/ | | | | | scheme authority path query fragment | _____________________|__ / \ / \ urn:example:animal:ferret:nose
-
The params are seperated by
&
symbol, blank space is seperated by+
. -
Post
send data by message body. It usually setContent-type
to eitherapplication/x-www-form-urlencoded
, ormultipart/form-data
. -
When you receive a POST request, you should always expect a payload(message body in HTTP terms) which have sending data. The data format will be the same as GET request's query string.
-
POST request data size can be set by HTTP server's configuration.
##2. Params
-
All sending data will be parsed to
params
hash in rails.# CASE 1 # # GET clients: /clients?status=activated params[:status] == "activated" # CASE 2 # # POST /clients, form does not custom its sending data to a AR model. <%= form_tag 'clients', method: "POST" do %> <%= text_field_tag 'name' %> <%= submit_tag "Send Client" %> <% end %> params # => # { "name"=>"asdas", # "commit"=>"Send Client", # "controller"=>"welcome", # "action"=>"client_create" } # CASE 3 # # POST /clients, form data is customed to a user model <%= form_for :user, url: "/clients" do |f| %> <%= f.text_field 'name' %> <%= f.submit "Send" %> <% end %> # HTML code <form action="/clients" accept-charset="UTF-8" method="post"> <input type="text" name="user[name]" id="user_name"><br> <input type="text" name="user[email]" id="user_email"><br> <input type="password" name="user[password]" id="user_password"><br> <input type="submit" name="commit" value="register"> </form> params # => # { "user" => { "name"=>"ada", # "email"=>"[email protected]", # "password"=>"123456789" # }, # "commit"=>"register", # "controller"=>"welcome", # "action"=>"client_create" }
####2.1 ERB trim space
What is the difference between
<%
,<%=
,<%#
and-%>
in erb in rails.
####2.2 Hash and Array in params
-
To send an array of values, append an empty pair of square brackets "[]" to the key name:
# GET /clients?ids[]=1&ids[]=2&ids[]=3 # The actual URL in this example will be encoded as: # "/clients?ids%5b%5d=1&ids%5b%5d=2&ids%5b%5d=3" # as the "[" and "]" characters are not allowed in URLs. # But browser will encode, decode for you. params[:ids] = [1, 2, 3] # To send a hash, include a key name inside the brackets. <form accept-charset="UTF-8" action="/clients" method="post"> <input type="text" name="client[name]" value="Acme" /> <input type="text" name="client[phone]" value="123" /> <input type="text" name="client[address][postcode]" value="123" /> <input type="text" name="client[address][city]" value="City" /> </form> params[:client] # { "name" => "Acme", # "phone" => "12345", # "address" => { "postcode" => "12345", "city" => "Carrot City" } # }
####2.3 JSON parameters
-
If the
Content-Type
header of your request is set toapplication/json
, Rails will automatically load your parameters into the params hash.// JSON data { "company": { "name": "acme", "address": "123 Carrot Street" } }
To:
params[:company] == / { "name": "acme", "address": "123 Carrot Street" }
-
If you've turned on
config.wrap_parameters
in your initializer or calledwrap_parameters
in your controller, you can safely omit the root element in the JSON parameter. In this case, the parameters will be cloned and wrapped with a key chosen based on your controller's name. So the above JSON POST can be written as:// JSON input { "name": "acme", "address": "123 Carrot Street" }
Assuming that you're sending the data to
CompaniesController
, params is to:# params will have { name: "acme", address: "123 Carrot Street", company: { name: "acme", address: "123 Carrot Street" } }
-
Parsing XML parameters will need
actionpack-xml_parser
gem.
####2.4 Routing Parameters
-
params
hash always havecontroller
andaction
keys. But you should access them bycontroller_name
andaction_name
instead. -
You can also add key value pairs to
params
hash and dynamically setting route param in yourroutes.rb
.# routes.rb get 'clients/:status' => "welcome#get_index", foo: 'bar' # GET request "clients/bb" params # => { "foo"=>"bar", "controller"=>"welcome", # "action"=>"get_index", "status"=>"bb"} controller_name # => "welcome" action_name # => "get_index"
####2.5 Default URL Options
-
You can also add query strings to your URL request. Define a
default_url_options
method in your controller and must return hash. -
For performance reasons, the returned hash is cached, there is at most one invocation per request.
-
That query string will append to any URL generation methods, such as generate action path for
form_for
method, orurl_for
method. It can be overridden by options passed tourl_for
. -
That hash will set its key-value pairs to
params
when GET/POST request comes inot server.# application_controller.rb def default_url_options { hello: "default_url_options" } end # routes.rb post '/' => "welcome#create" # request will be actually as: POST "/?hello=default_url_options" params # => { "user"=>{"name"=>"", "email"=>"[email protected]", "password"=>"123"}, # "commit"=>"register", # "hello"=>"default_url_options", # "controller"=>"welcome", # "action"=>"create" # }
-
We can override the url default options in our customed controller. Which will take place the method in application controller.
# welcome_contrller.rb def default_url_options if request.env["HTTP_ACCEPT_LANGUAGE"].include? "en" { my_hello: "my_default_url_options" } else { localization: "none" } end end # form in html code, action has appended that query string. <form action="/?my_hello=my_default_url_options" accept-charset="UTF-8" method="post"> # ... </form> params # { "user"=>{"name"=>"", "email"=>"[email protected]", # "password"=>"123"}, "commit"=>"register", # "my_hello"=>"my_default_url_options" # }
-
Using strong parameters to prevent model's unallowed attrtibutes accidentally accessed by users.
#####Must Read: Strong parameters by example. #####http://patshaughnessy.net/2014/6/16/a-rule-of-thumb-for-strong-parameters
-
If we missing
required
param, server will throw exception and return 400 bad request by default. -
require
a param means it requires a key(model) and filter out other keys.permit
accept the permitted scalar values only, so hash or array can not be directly accepted bypermit
. -
To get attribute with array value from permit, we can declare as below:
params = ActionController::Parameteres.new(usernames: ["John", "Las"]) params.permit(usernames: [])
-
To get attribute with hash value from permit, we can declare as below:
params = ActionController::Parameteres.new(usernames: {"a" => 1, "b" => 2}) params.permit(usernames: [:a, :b])
-
Though
require
orrequire.permit
may produce same hash result, but it may raiseActiveModel::ForbiddenAttributesError
if withoutpermit
.params = ActionController::Parameters.new(user: { username: "john" }) params.require(:user) # => { "username" => "john" } params.require(:user).permit(:username) # => { "username" => "john" } params.require(:user).permitted? # => false # When you inject to mass assignment, # This raise ActiveModel::ForbiddenAttributesError. User.new(params.require(:user)) # ActiveModel::ForbiddenAttributesError params.require(:user).permit(:username).permitted? # => true
-
Strong parameters must be permitted. It can be required to specific attributes in params.
-
Using
require
withpermit
will only return the values, or nested hash, but not the parent one.params = ActionController::Parameters.new(user: { username: "john" }) params.permit(user: [ :username ]) # => { "user" => {"username"=>"john"} } params.require(:user).permit(:username) # => { "username" => "john" }
-
require
returns the actual value of the parameter, unlikepermit
which returns the actual hash.params = ActionController::Parameters.new(username: "john", password: {a: 1}) params.require(:usernames) # "John" params.require(:password) # {a: 1} params.permit(:usernames) # { usernames: "john"} params.permit(password: [:a]) # { password: {a: 1}}
-
Sometimes we can not unsure the attributes in nested hash, ex: JSON data. Then we need to use
tap
workaround this. So we can mixup other values which out side the scope of strong parameters:params = ActionController::Parameters.new(user: { username: "john", data: { foo: "bar" } }) # let's assume we can't do below, # because the data hash can contain any kind of data params.require(:user).permit(:username, data: [ :foo ]) # we need to use the power of ruby to do this "by hand" params.require(:user).permit(:username).tap do |whitelisted| whitelisted[:data] = params[:user][:data] end # Unpermitted parameters: data # => { "username" => "john", "data" => {"foo"=>"bar"} } # Or mixup out side the scope of strong parameters. def product_params params.require(:product).permit(:name, data: params[:product][:data].try(:keys)) end
-
Only one key can be required, but multiple permitted scalar values can be permitted.
# GET /?name[]=1&name[]=2&name[]=3&kk[a]=1&kk[b]=2 params # => { "utf8"=>"✓", # "authenticity_token"=>"Hbw===", # "name"=>["1", "2", "3"], # "kk"=>{"a"=>1, "b"=>2, "c"=> [3,4,5]}}, # "commit"=>"Send Client", # "controller"=>"welcome", # "action"=>"client_create" } params.require(:name) # => ["1", "2", "3"] # permit not accept key's value is hash or array. params.permit(:name) # ActionController::UnpermittedParameters: # found unpermitted parameters: # utf8, authenticity_token, name, commit, kk params.require(:action) # => "client_create" params.require(:action, :controller) # => ArgumentError: wrong number of arguments (2 for 1) # permit an array params.permit(name: []) # [1, 2, 3]
-
By default,
config.action_controller.action_on_unpermitted_parameters
is set to:log
. It will omit the unpermitted attributes and give warning only. You can respond it by set the property to:rasie
. This will lead the server respond back 500 sever internal error request.# application.rb, deveopment.rb, or any environment.rb config.action_controller.action_on_unpermitted_parameters == :log # default is :log #welcome_controller.rb class WelcomeController < ApplicationController def index user_params end private def user_params params.permit(:name, :password) end end # GET /?email=a.mail.com&name=&password=1234 user_params # Unpermitted parameter: email # => {"name"=>"", "password"=>"1234"} # Now set :log to :raise config.action_controller.action_on_unpermitted_parameters = :raise # When we call user_params in our controller, it will raise exception. user_params # ActionController::UnpermittedParameters: # found unpermitted parameter: email. # And return 500 server internal error response.
-
If your required parameters is missing, then you can rescue the exception and customized the response by applying class method
rescue_from
in your controller to respond the request in your way.# welcome_controller.rb class WelcomeController < ApplicationController rescue_from ActionController::ParameterMissing do |param_miss_excp| render :text => "Required parameter missing:" + "#{parameter_missing_exception.param}", :status => :bad_request end end # GET /?email=a.mail.com&name=&password=1234 params.require(:user) # ActionController::ParameterMissing: # param is missing or the value is empty: user # Then rescued to 400 bad request.
-
To Permit an Array with hash values, use hash brackets or none:
params = ActionController::Parameters.new( title: "post", comment: [{text: "hi"}, {text: "Hi 2"} ]) #=> {"title"=>"post", "comment"=>[{"text"=>"hi"}, {"text"=>"Hi 2"}]} # permit key comment's array value params.permit(:title, { comment: [:text] }) # or params.permit(:title, comment: [:text]) params.permit(:title, {comment: [:text]}) == params.permit(:title, comment: [:text]) # true
##3. Session
-
4 ways to store sessions:
ActionDispatch::Session::CookieStore # Stores everything on the client. ActionDispatch::Session::CacheStore # Stores the data in the Rails cache. ActionDispatch::Session::ActiveRecordStore # Stores the data in a database using Active Record. # (require activerecord-session_store gem). ActionDispatch::Session::MemCacheStore # Stores the data in a memcached cluster # (this is a legacy implementation; consider using CacheStore instead).
-
All session stores use a cookie to store a unique ID for each session (you must use a cookie, Rails will not allow you to pass the session ID in the URL as this is less secure).
-
For most stores, this ID is used to look up the session data on the server, e.g. in a database table. There is one exception, and that is the default and recommended session store - the CookieStore - which stores all session data in the cookie itself.
The cookie data is cryptographically signed to make it tamper-proof. And it is also encrypted so anyone with access to it can't read its contents. Rails will not accept it if it has been edited.
-
The CookieStore can store around 4kB of data. Storing large amounts of data in the session is discouraged no matter which session store your application uses.
-
You should especially avoid storing complex objects (anything other than basic Ruby objects, the most common 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.
-
Consider
ActionDispatch::Session::CacheStore
if your user sessions don't store critical data or don't need to be around for long periods. The downside is that the sessions will be ephemeral and could disappear at any time. -
Change session store mechanism:
# config/initializers/session_store.rb # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information. # create the session table by "rails g active_record:session_migration" Rails.application.config.session_store :active_record_store # Be sure to restart your server when you modify this file. Rails.application.config.session_store :cookie_store, key: '_your_app_session', domain: ".example.com"
-
Session is server side hash which locate its session id as key to identify user and user id.
-
Cookie is a file store in client side, but each GET request header has
Set-Cookie
field which can modify cookie from server to client side response. Each client request server by setting session id inCookie
field to let server identify its user id. -
All the session data in cookie by
Session::CookieStore
has been encrypted.Demo::Application.config.session_store :cookie_store, key: '_demo_session' session[:github_username] = 'neerajdotname' # check cookie with _demo_session key # "BAh7CEkiD3Nlc3...==--b5bcce534ceab56616d4a215246e9eb1fc9984a4" # unescaped chars unescaped_content = URI.unescape(content) # => "BAh7CEkiD3Nlc3...==--b5bcce534ceab56616d4a215246e9eb1fc9984a4" # seperate from data and digest data, digest = unescaped_content.split('--') # => ["BAh7CEkiD3Nlc...==", "b5bcce534ceab56616d4a215246e9eb1fc9984a4"] Marshal.load(::Base64.decode64(data)) # => { "session_id"=>"80dab78baffa77655fef0e13a3ba208a",
```
####3.1 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 passing error messages etc.
class LoginsController < ApplicationController def destroy session[:current_user_id] = nil flash[:notice] = "You have successfully logged out." redirect_to root_url # or customized in redirection method redirect_to root_url, notice: "You have logged out." redirect_to root_url, alert: "You're stuck here!" redirect_to root_url, flash: { referral_code: 1234 } end end
-
You can then display the flash message in view template:
<html> <!-- <head/> --> <body> <% flash.each do |name, msg| -%> <%= content_tag :div, msg, class: name %> <% end -%> <p class="well"><%= flash[:alert] %></p> <!-- more content --> </body> </html>
-
If you want a flash value to be carried over to another request, use the
keep
method: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 # Will persist all flash values. flash.keep # You can also use a key to keep only some kind of value. # flash.keep(:notice) redirect_to users_url end end
-
By default, adding values to the flash will make them available to the next request(redirection), but sometimes you may want to access those values in the same request(render to response).
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
-
Instead of stroing and encrypted data in session then using
Session::CokkieStore
to store it to cookie, you can just put the data to cookie instead.class CommentsController < ApplicationController # Auto-fill the commenter's name if it has been stored in a cookie def new @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] # Remember the commenter's name. cookies[:commenter_name] = @comment.author else # Delete cookie for the commenter's name cookie, if any. cookies.delete(:commenter_name) end redirect_to @comment.article else render action: "new" end end end
-
Note that while for session values you set the key to
nil
, to delete a cookie value you should usecookies.delete(:key)
. -
To know more about how cookie store sensetive data and data transform with JSON format, check cookie jar in that subpart:
http://edgeguides.rubyonrails.org/action_controller_overview.html#cookies
-
Instead
redirect_to
andrender
helpers, callrespond_to
: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
-
We can add filter methods before or after actions.
class ApplicationController < ActionController::Base before_action :require_login after_action :forward_notifications, only: :create def create; end private def require_login unless logged_in? flash[:error] = "You log in to access this section" redirect_to new_login_url # halts request cycle end end def forward_notifications # after action cannot stop that action, # but can do some background jobs. end end
-
"around" filters are responsible for running their associated actions by yielding, similar to how Rack middlewares work.
class ChangesController < ApplicationController around_action :wrap_in_transaction, only: :show private def wrap_in_transaction ActiveRecord::Base.transaction do begin yield # yield to that show action code. ensure raise ActiveRecord::Rollback end end end end
-
We can also use filters by
*_action
block,around
action also needs yield:class ApplicationController < ActionController::Base # private instance method :logged_in? before_action do |controller| unless controller.send(:logged_in?) flash[:error] = "You logged in to access this section" redirect_to new_login_url end end end
-
Or we can use a filter class. The filter class must implement a method with the same name as the filter, so for the
before_action
filter, the class must implement abefore
class method, and so on. Thearound
method mustyield
to execute the action.class ApplicationController < ActionController::Base before_action FilterClass end class Filter def self.before(controller) unless controller.send(:logged_in?) controller.flash[:error] = "You..." controller.redirect_to controller.new_login_url end end end
-
around_action
block:around_action do |controller| if params[:action] == "create" check_creation controller else controller.send(params[:action]) end end def create; end def check_creation(controller) puts (params["action"]).append(" around action!") # create action controller.send(params["action"]) puts "Done the around" end # Log: # create around action! # begin transaction # ... # commit transaction # Redirected to http://localhost:3000/?my_hello=my_default_url_options # Done the around # Completed 302 Found in 38379ms (ActiveRecord: 9.7ms)
-
The first step to avoid this is to make sure all "destructive" actions (
create
,update
anddestroy
) can only be accessed with non-GET requests. -
Rails add hidden field to
form
which prevent csrf attack.
-
We can call
request
orresponse
object to know the header or any other details in that request/response.class SomeController < ApplicationController def index p request.env["QUERY_STRING"] end end
-
Rails collects all of the parameters sent along with the request in the params hash, whether they are sent as part of the query string or the post body.
request.query_parameters # => {"my_hello"=>"my_default_url_options"} request.path_parameters # => {:controller=>"welcome", :action=>"create"} request.request_parameters # parameters from message body # => { "utf8"=>"✓", # "authenticity_token"=>"CQ==", # "user"=>{"name"=>"", "email"=>"[email protected]", # "password"=>"123456789"}, # "commit"=>"register"} params # { "utf8"=>"✓", # "authenticity_token"=>"CQ==", # "user"=>{"name"=>"", "email"=>"[email protected]", # "password"=>"123456789"}, # "commit"=>"register", # "my_hello"=>"my_default_url_options", # "controller"=>"welcome", # "action"=>"create"}
-
You can customized your repsonse with customed headers. If you want to add or change a header, just assign it to
response.headers
this way, Rails will set some of them automatically:response.header["Content-type"] = "application/pdf"
-
Beware if you have
redirect_to
orrender
helpers which will override your repsonse settings, put your customized response setting to last line of your action method.
-
Two basic authentications:
Basic Authentication
Digest Authentication -
As an example, consider an administration section which will only be available by entering a username and a password into the browser's HTTP basic dialog window by
http_basic_authenticate_with
.class AdminsController < ApplicationController http_basic_authenticate_with name: "humbaba", password: "5baa61e4" end
-
HTTP digest authentication is superior to the basic authentication as it does not require the client to send an unencrypted password over the network (though HTTP basic authentication is safe over HTTPS). So the actual password digest is encrypted and decrypted in server side only.
-
It still pop dialog window, but the password can be decrypted later in server side with ha1 digest hash.
require 'digest/md5' class PostsController < ApplicationController REALM = "SuperSecret" USERS = {"dhh" => "secret", #plain text password "dap" => Digest::MD5.hexdigest(["dap", REALM, "secret"].join(":"))} #ha1 digest password before_action :authenticate, except: [:index] def index render plain: "Everyone can see me!" end def edit render plain: "I'm only accessible if you know the password" end private def authenticate authenticate_or_request_with_http_digest(REALM) do |username| USERS[username] end end end
-
The
authenticate_or_request_with_http_digest
block must return the user's password or the ha1 digest hash. Returningfalse
ornil
from the block will cause authentication failure.
-
Sometimes you may want to send a file to the user instead of rendering an HTML page. All controllers in Rails have the
send_data
and thesend_file
methods, which will both stream data to the client. -
For
send_data
, to tell the browser a file is not meant to be downloaded, you can set the:disposition
option to inline. The opposite and default value for this option is attachment.#####http://apidock.com/rails/ActionController/Streaming/send_data
# send_data require "prawn" class ClientsController < ApplicationController # Generates a PDF document with information on the client and # returns it. The user will get the PDF as a file download. def download_pdf client = Client.find(params[:id]) send_data generate_pdf(client), filename: "#{client.name}.pdf", type: "application/pdf" end private def generate_pdf(client) Prawn::Document.new do text client.name, align: :center text "Address: #{client.address}" text "Email: #{client.email}" end.render end end
-
send_file
will read and stream the file 4kB at the time, avoiding loading the entire file into memory at once. You can turn off streaming with the:stream
option or adjust the block size with the:buffer_size
option.class ClientsController < ApplicationController # Stream a file that has already been generated and stored on disk. def download_pdf client = Client.find(params[:id]) send_file("#{Rails.root}/files/clients/#{client.id}.pdf", filename: "#{client.name}.pdf", type: "application/pdf") end end
-
If
:type
is not specified, it will be guessed from the file extension specified in:filename
. If the content type is not registered for the extension,application/octet-stream
will be used. -
In REST terminology, the PDF file from the example above can be considered just another representation of the client resource. Here's how you can rewrite the example so that the PDF download is a part of the show action, without any streaming:
class ClientsController < ApplicationController # The user can request to receive this resource as HTML or PDF. def show @client = Client.find(params[:id]) respond_to do |format| format.html format.pdf { render pdf: generate_pdf(@client) } end end end
-
Inorder to make above code work, you have to register MIME type to Rails:
Configuration files are not reloaded on each request, so you have to restart the server in order for their changes to take effect.
# config/initializers/mime_types.rb Mime::Type.register "application/pdf", :pdf
-
Now the user can request to get a PDF version of a client just by adding ".pdf" to the URL:
GET /clients/1.pdf
-
The
ActionController::Live
module allows you to create a persistent connection with a browser.class MyController < ActionController::Base include ActionController::Live def stream response.headers['Content-Type'] = 'text/event-stream' 100.times { response.stream.write "hello world\n" sleep 1 } ensure response.stream.close end end
-
Forgetting to close the stream will leave the socket open forever. We also have to set the content type to
text/event-stream
before we write to the response stream. This is because headers cannot be written after the response has been committed (when response.committed? returns a truthy value), which occurs when you write or commit the response stream. -
Another Example, show the lyrics on time:
class LyricsController < ActionController::Base include ActionController::Live def show response.headers['Content-Type'] = 'text/event-stream' song = Song.find(params[:id]) song.each do |line| response.stream.write line.lyrics sleep line.num_beats end ensure response.stream.close end end
-
Stream Considerations:
- Each response stream creates a new thread and copies over the thread local variables from the original thread. Having too many thread local variables can negatively impact performance. Similarly, a large number of threads can also hinder performance.
- Failing to close the response stream will leave the corresponding socket open forever. Make sure to call close whenever you are using a response stream.
- WEBrick servers buffer all responses, and so including ActionController::Live will not work. You must use a web server which does not automatically buffer responses.
-
Sometime you don't want to log too much in production env.
# filter out sensetive request parameters config.filter_parameters << :password # Sometimes it's desirable to filter out from log files # some sensitive locations your application is redirecting to. config.filter_redirect << 's3.amazonaws.com' config.filter_redirect.concat ['s3.amazonaws.com', /private_path/] # Matching URLs will be marked as '[FILTERED]'
-
When excpetion throwed, Rails will display a simple "500 Server Error" message to the user, or a "404 Not Found" if there was a routing error or a record could not be found.
-
The default 500 or 404 message are a staitc html file in public folder. They are static, you can customized but not able to use any template engine to it(ERB, Haml, Slim).
-
To address these error message, call
rescue_from
with block or:with
method:class ApplicationController < ActionController::Base rescue_from ActiveRecord::RecordNotFound, with: :record_not_found private def record_not_found render plain: "404 Not Found", status: 404 end end
-
You can also create a customed Excpetion class, which raise an exception and rescued later:
class ApplicationController < ActionController::Base rescue_from User::NotAuthorized, with: :user_not_authorized private def user_not_authorized flash[:error] = "You don't have access to this section." redirect_to :back end end class ClientsController < ApplicationController # Check that the user has the right authorization to access clients. before_action :check_authorization # Note how the actions don't have to worry about all the auth stuff. def edit @client = Client.find(params[:id]) end private # If the user is not authorized, just throw the exception. def check_authorization raise User::NotAuthorized unless current_user.admin? end end
-
Certain exceptions are only rescuable from the
ApplicationController
class, as they are raised before the controller gets initialized and the action gets executed.
-
You can use the
force_ssl
method in your particular controller to enforce that, provideonly
orexcept
to limit the HTTPS to particular action:class DinnerController force_ssl only: :create # or force_ssl except: :index end