0

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?

Just a learner
  • 26,690
  • 50
  • 155
  • 234

2 Answers2

2

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.

BryanH
  • 5,826
  • 3
  • 34
  • 47
gdpelican
  • 568
  • 4
  • 12
2

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.

JTG
  • 8,587
  • 6
  • 31
  • 38