简体   繁体   中英

Rails: What determines name of "params" passed?

So I can't quite find the answer on the internet for this seemingly simple problem.

What I've gone through tutorial apps, for say a basic CRUD app...and lets say your normal User create/edit/update/delete pages.

Typically you see something like:

params.require(:user).permit(:name, :email, :password, :password_confirmation)

So this means the params passed is params(:user) right?

However sometimes, such as when doing a link_to and passing something to to a POST request (Such as a patch or update or something similar) the param is simply params[:id] . What determines what the params(:<name>) is going to be called?

It seems to be dependent on forms...but sometimes not? Does it just default to id otherwise or something?

Rails guide mentions this

params is combination of:

  1. routing parameters
  2. GET-parameters ( example.org/page?some_param=value )
  3. POST parameters (form data, decoded json, etc.)

params[:id] usually comes from routing parameters ( /users/:id ), there can be other route params (for example other common case is nested routes like /users/:user_id/some_other_resources/:id - there will be :user_id and :id ) and by convention saved object is passed in params[:model_name]

Parameters are part of HTTP requests. HTTP requests have no restrictions on what can be sent as a parameter (outside of size of data being sent). So, you can send a request to any route on your server with params.

Rails attempts to prevent any evil, sneaky, people from injecting parameters and values where they don't belong. We can do that by creating a method that wraps our params object in a specified structure:

params.require(:user).permit(:name, :email, :password, :password_confirmation)

This means params must be sent in this format:

user: {
  name: "name",
  password: "password",
  password_confirmation: "password"
}

If you check your logs in development, Rails will display your params (should any be sent) in each request. If your params are not in that format (with a user at the root level) and you use the method user_params , it will throw an error. user is required . And should someone send the parameters:

user: {
  name: "name",
  pseudonym: "sneaky param",
  password: "password",
  password_confirmation: "password"
}

Rails will still accept name , password , and password_confirmation , but it will reject pseudonym because it is not permitted by your method user_params .

You'll see in a lot of code, people grab the params[:id] value directly. That's because we're often only using that to read or destroy an item. *_params methods are usually reserved for CREATE and UPDATE actions in the controller because that's where we are injecting params.

It's not technically necessary. Rails is already sanitizing user input in the Active Record queries. So, it's not a direct requirement for a secure app. You could pull the params directly from the params hash, rather than using this method. But it certainly keeps your code DRY. It also ensures you're not giving user's access to important metadata in your model. For example, if you're SO, you might (though unlikely) have an upvote column for my post. If you whitelist all params and just accept all params into the Post.update(params) method, I could send a POST request with the params upvotes: 1,000,000 . I don't think they'd like that at all.

It can be determined by the route, by the input tag or by you.

By the route:

rails routes -g user 
   Prefix Verb   URI Pattern               Controller#Action
   signup GET    /signup(.:format)         users#new
    users GET    /users(.:format)          users#index
          POST   /users(.:format)          users#create
edit_user GET    /users/:id/edit(.:format) users#edit
     user GET    /users/:id(.:format)      users#show
          PATCH  /users/:id(.:format)      users#update
          PUT    /users/:id(.:format)      users#update
          DELETE /users/:id(.:format)      users#destroy

Here, params[:id] is set by the url helper like edit_user_path(@user) . You can set your own param name in config/routes.rb :

get 'profile/:user_id', to: 'users#show'
rails routes -g profile 
Prefix Verb URI Pattern                 Controller#Action
       GET  /profile/:user_id(.:format) users#show

By the input:

<%= form_for @user... do |f| %>
  <%= f.text_field :name
<% end %>

Here, the form sets params: {user: {name: some_value}} , because the model object used by the form is User and the column name is name .

And by you:

link_to 'Profile', user_path(@user, locale: 'en')

which outputs: <a href=\\"/users/1?locale=en\\">Profile</a>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM