geoff swartz
geoff swartz

Reputation: 5965

changing parameters in rails controller

I have a controller with the following methods

 def create
    @todo = Event.new(event_params)
    ...
 end

 def event_params
   form_params = [:title, :type, :owner_id, :note, :occurred, :due]
   form_params[:due].strftime!("%Y-%m-%d")
   params.permit(form_params)
 end

I found that when I post a date (:due or :occurred) to the create method with a format of mm/dd/yyyy instead of dd/mm/yyyy I'm getting an argument out of range for a date such as 10/30/2014. So I'm trying to convert the date values in the parameters before it calls Event.new

The line - form_params[:due].strftime!("%Y-%m-%d") - is not working and after quite a bit of googling, I can't seem to figure out the right way to modify the value of a parameter. The error I get currently for that line is "no implicit conversion of Symbol into Integer". How can I do this? Thanks.

Upvotes: 1

Views: 3197

Answers (3)

Ryan Francis
Ryan Francis

Reputation: 645

Super late to the game but you may consider using this gem: github.com/launchpadlab/decanter

It allows you to easily define how incoming params should be parsed.

More on it here: https://medium.com/launchpad-lab/the-missing-step-in-rails-controllers-82aaa9172165

Upvotes: 0

twonegatives
twonegatives

Reputation: 3438

Well, let's discuss each line of your code to make it clear where the mistake is.

form_params = [:title, :type, :owner_id, :note, :occurred, :due]

First, you declare an array of symbols and assign that array to form_params variable. It's just a simple plain array, not an associative one, so you can access its values using indexes only, e.g. form_params[0] would return :title, but form_params[:due] is a runtime error as :due is not an integer index. Actually, the purpose of event_params method should be as simple as stating which parameters you allow to be mass-assigned to your objects, so it should look like

params.permit([:title, :type, :owner_id, :note, :occurred, :due])

Getting further, your aim is to edit parameters which came from client-side. As of various dates formats parsing, please refer to this topic.


Disclaimer: It could be much more elegant to force users to pass due date in conventional %Y-%m-%d format. Please give a look to rails dates helper methods.


That parameters reside in params hash, so you could rewrite appropriate key:

def event_params
  params["due"] = Date.strptime(params["due"], "%m/%d/%Y").to_s
  # here we've converted date format to standard %Y-%m-%d
  params.permit([:title, :type, :owner_id, :note, :occurred, :due])
end

This should do two things:

  1. Replace user's due with appropriate date format
  2. Allow enumerated keys to be mass-assigned for your object

And the rest of your code should work fine with this correction:

def create
  @todo = Event.new(event_params)
  ...

However, beware of side effects:

  1. Using event_params restricts you from getting actual %m/%d/%Y user input now.
  2. Malefactor would be able to pass some unparsable string instead of %m/%d/%Y formatted date and it would end in runtime error.

Upvotes: 2

Jim
Jim

Reputation: 475

You are assigning form_params an array of symbols, and you can't reference an element of an array by symbol, thus your error. You probably want that to look like this:

form_params = params.permit(:title, :type, :owner_id, :note, :occurred, :due)

which will give you the hash you are looking for.

Edit: at first I didn't check the date manipulation you were attempting. You would need to use Date.strptime to convert your string to a date, but you need to know the date format. Unfortunately, you cannot accurately guess that type of thing. If you know the date will be mm/dd/yyyy, you could convert formats like this:

params[:due] = Date.strptime(params[:due], '%m/%d/%Y').strftime("%Y-%m-%d")

Upvotes: 1

Related Questions