Gordon White
Gordon White

Reputation: 27

Rails Strong Parameters - create action with foreign key parameters

I have three models, Server has many maintenances and Maintenance belongs to Server and User.

create_table :maintenances do |t|
  t.references :server, foreign_key: true
  t.references :user, foreign_key: true
  t.string :name
  t.text :content
end

In console I can create records as follows:

Server.create(:hostname => "Sissy", :description => "Webserver")
Maintenance.create(:server_id => 1, :user_id => 1, :name => "Test", :content => "Test" )

My Question is: How can I do this in my Controller create action? Problem is that :user_id is not part of the maintenance params hash, so if I write

def create
  @server = Server.find(params[:id])
  @maintenance = @server.maintenances.create!(maintenance_params)
end

  private
    def maintenance_params
      params.require(:maintenance).permit(:user_id => current_user.id, 
                                          :id, 
                                          :name, 
                                          :content)    
    end

I'm getting

Syntax error, unexpected ',', expecting =>
...ser_id => current_user.id, :id, :name, :content, :start, :pl...
...                               ^):

app/controllers/maintenances_controller.rb:41: syntax error, unexpected ',', expecting =>

Upvotes: 1

Views: 1343

Answers (3)

max
max

Reputation: 101811

A good way is by passing a block to the create! method:

@maintenance = @server.maintenances.create!(maintenance_params) do |m|
  m.user = current_user
end

The record is yielded to the block (before it is validated/saved).

This also works with new, create, update and update!.

But you should consider if you should be using the bang method create! here as it will raise an uncaught ActiveRecord::RecordNotValid error if any of the validations fail.

def create
  @server = Server.find(params[:id])
  @maintenance = @server.maintenances.new(maintenance_params) do |m|
    m.user = current_user
  end
  if @maintenance.save
    redirect_to @maintenance
  else
    render :new 
  end
end

The ActiveRecord::Persistence bang methods should only really be used in things like seed files or where a record not passing the validations is an exceptional event.

Upvotes: 2

Navin
Navin

Reputation: 646

You can add , user_id inside your create action itself. Try this.

def create
  @server = Server.find(params[:id])
  params[:maintenance][:user_id] = current_user.id
  @maintenance = @server.maintenances.create!(maintenance_params)
end

Upvotes: 3

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230286

Yes, you can't do anything like that in strong_params method. Nor is it its purpose. Separate the whitelisting and default params.

I usually do it like this:

def create
  @server      = Server.find(params[:id])
  @maintenance = @server.maintenances.create!(maintenance_params.merge(user_id: current_user.id))
end

private
def maintenance_params
  params.require(:maintenance).permit(:id, :name, :content)
end

Upvotes: 0

Related Questions