Just a learner
Just a learner

Reputation: 28622

Understanding of Rails 4's strong parameters

I'm totally new to Rails and I'm playing with it. Now I'm trying to understand the strong parameter feature introduced in Rails 4. Below is my code:

class PostsController < ApplicationController
  def index
  end

  def show
  end

  def create
    p = Post.new(create_post_params)
    p.save

    redirect_to p
  end

  def new
  end

  private

  def create_post_params
    params.require(:post).permit :title, :body
  end
end

Beside the controller, I also have a Post model with a title and a body. My question is what is this :post thing in params.require(:post).permit :title, :body? I write it as :post, is it because I'm currently inside the PostsController? Or I'm reading the properties of a Post?


Edit

Based on gdpelican's answer, if my new.html.erb is like this:

<h1>Create a post</h1>
<%= form_for :post, url: posts_path do |f| %>
  <div class="form-group">
    <%= f.label :title %>
    <%= f.text_field :title, class: "form-control" %>
    <p class="help-block">Please type the title of the post</>
  </div>

  <div class="form-group">
    <%= f.label :body %>
    <%= f.text_area :body, class: "form-control", rows: 5 %>
    <p class="help-block">Please type the body of the post</>
  </div>

  <%= f.submit class: "btn btn-primary" %>

<% end %>

It's the :post part in <%= form_for :post, url: posts_path do |f| %> determines that I should use :post in params.require(:post).permit :title, :body, right?

Upvotes: 0

Views: 374

Answers (2)

gdpelican
gdpelican

Reputation: 568

It is the name of the JSON wrapper of your form values.

The form will typically wrap the form parameters like so:

{
  post: {
    title: "Title",
    body:  "Body",
  }
}

When using something like form_for @post

In essence, params.require(:post).permit(:title, :body) is saying two things:

  1. my parameters must have a :post attribute
  2. the :post attribute may only have a title and a body parameters, and nothing else.

UPDATE

The parameters in form_for are what affect how your parameters are wrapped.

Generally, the name of the controller matches the name of the form parameters, so in most instances it's a safe assumption that a 'BooksController' will accept form parameters in a 'book' field.

Upvotes: 2

JTG
JTG

Reputation: 8836

Your parameters (typically) look like this

{"utf8"=>"✓", "authenticity_token"=>"...", "post"=>{"title"=>"My title", "body" =>"Body of my Post"}}

When you require a specific key from the parameters (for example post) Rails will throw an error if the hash it was passed doesn't have "post"=>{....}, then once it passes that check it permits the allowed keys and returns only the parameters nested under "post" hash allowed. To copy the api docs examples

params = ActionController::Parameters.new({
  person: {
    name: 'Francesco',
    age:  22,
    role: 'admin'
  }
})

params.require(:person).permit(:name, :age)
=>{"name"=>"Francesco", "age"=>22}

So after your strong params check, the return is a hash of :post parameters that you have allowed.

EDIT: To answer your second question.

That is one way of thinking about it. Your form syntax (form_for :post) is creating the post hash with the attributes nested inside, and sending it as part of the overall parameters hash. And your params.require(:post) is taking the entire params, and finding only the hash key it wants (post) and then permitting the keys that are inside the post hash.

Upvotes: 2

Related Questions