0

Reading and doing some RoR tutorials, they say that we should have a private method to request an object and indicate its properties. For example:

  def category_params
    params.require(:category).permit(:name)
  end

When I create a new category (the data in this example), I use in my create action:

@category = Category.new(category_params)

But, when I update a category, I can't do @category = Category.new(category_params) because the :category doesn't return in the params. To this situation, I saw in the comentaries of this question that the require(:category) need to be removed to the update action work. That fix the problem, but in other way, when I create a new category using the category_params so, always an empty object is saved.

Have two private methods, onde with require and other without isn't a good practice, or is? What is the good practice in this case?

EDIT 1 (my update and edit action):

def edit
  @category = Category.find(params[:id])
end

def update
  @category = Category.find(params[:id])

  if @category.update_attributes(category_params)
    # TO DO
  else
    render 'edit'
  end
end
Community
  • 1
  • 1
rwehresmann
  • 1,108
  • 2
  • 11
  • 27
  • You can use it on update. Can you post your full code? – j-dexx Feb 19 '16 at 13:30
  • I updated the post (is in EDIT 1). – rwehresmann Feb 19 '16 at 13:40
  • Try creating a scaffolded controller - `rails g scaffold category name:string`. I'm not saying you should use it but it will show you the rails way to handle params. – max Feb 19 '16 at 13:41
  • 2
    Fix it by having edit form post the correct params (nested under `:category`, same as in `create` action) – Sergio Tulentsev Feb 19 '16 at 13:42
  • Also ignore that question that you linked to - the answer is just telling him how to fix his existing idiosyncratic code - not the *Rails way* or a best practice in any way. – max Feb 19 '16 at 13:45
  • What is in your edit action and form? – j-dexx Feb 19 '16 at 13:50
  • @max, about the question that I linked, good to know (I'm new in Ruby). About the scaffold, I tryed, but at the moment, I really don't understand what I'm forgetting. – rwehresmann Feb 19 '16 at 15:54
  • @j-dexx, I updated the post with my edit action. I haven't created my view with the form yet. I think that doesn't affects now, because I don't receive the message that the view is missing (as opposed when I took the `require` from the `category_params` in my tests). – rwehresmann Feb 19 '16 at 16:01

1 Answers1

2

I think you are just confused about what strong parameters is supposed to do - its basically just whitelisting parameters for mass assignment.

Mass assignment is when you instantiate a new record with attributes from a hash or update from a hash. Your update action is perfectly fine although you would usually use #update instead of #update_attibutes.

The smart way to do this is by using a private method in your controller so that you don't have to do the exact same whitelisting twice in the update and create action.

class CategoriesController

  before_action :set_category, only: [:show, :edit, :update, :destroy]

  def new
    @category = Category.new
  end

  def create
    @category = Category.create(category_params)
    respond_with(@category)
  end

  def edit
  end

  def update
    if @category.update(category_params)
    # TO DO
    else
      render 'edit'
    end
  end

  # ...

  private

    def set_category
      @category = Category.find(params[:id])
    end

    def category_params
      params.require(:category).permit(:name, :foo, :bar)
    end

end

we setup the form like so:

app/views/categories/_form.html.erb

<%= form_for(@category) do |f| %>
  <div class="field">
    <%= f.label :name %>
    <%= f.text_field :name %>
  </div>

  <%= f.submit %>
<% end %>

We can use the exact same form for both creating new records and editing.

app/views/categories/new.html.erb:

<%= render partial: "form" %>

app/views/categories/update.html.erb:

<%= render partial: "form" %>

Note that in some cases you might want allow certain attributes for one action but not for another. In that case you just create two strong parameter methods:

class CategoriesController

  before_action :set_category, only: [:show, :edit, :update, :destroy]

  def new
    @category = Category.new
  end

  def create
    @category = Category.create(create_params)
    respond_with(@category)
  end

  def edit
  end

  def update
    if @category.update(update_params)
    # TO DO
    else
      render 'edit'
    end
  end

  # ...

  private

    def set_category
      @category = Category.find(params[:id])
    end

    def create_params
      params.require(:category).permit(:name, :foo, :bar)
    end

    def update_params
      params.require(:category).permit(:name)
   end

end
max
  • 96,212
  • 14
  • 104
  • 165