Tim
Tim

Reputation: 1005

Rails - passing additional variables on .create

I'm trying to put into practise using skinny controllers and fat models, however in order to do this I find myself needing to pass additional variables into the .create method.

So for example where I had:

@app =  App.new(app_params)

def app_params
  params.require(:app).permit( :name,  :description)
end

Now I want to also pass along say, a session held user_id, and a reference to a permission group. So hopefully something like the following pseudo code:

@app = App.create(app_params, session[:user_id], app_permission_id)

The user_id and app_permission_id would not be persisted but would be available I'd hope somewhere like in the after_create callback within the model, so I can then do some further work, for example creating a log entry of the creation, associated to the calling user.

I'm not so keen on just adding them in the form as hidden fields (to hide implementation from users). I think there is a possible approach using .merge? if that's the way, the I guess I pull them out using a virtual attribute.

Any advise on the best/cleanest approach would be much appreciated. I think I'd prefer to override the .create method somehow (but only in terms of the cleanest implementation from the controller side).

Upvotes: 5

Views: 2843

Answers (3)

Richard Peck
Richard Peck

Reputation: 76784

The two answers describing .merge are correct; let me explain why

--

Params

When processing your params at controller level, and handling with strong_params, Rails basically "passes" the data through to your model, like this:

"params" => {
   "app" => {
      "name" => "data",
      "description" => "data",
    }
}

This is what the typical form_for params object sends through to your controller. When you pick up the data through the strong_params method, you basically just "permit" the various pieces of data to pass through to the model.

Remember, strong_params are designed to help prevent mass_assignment, which means the method is designed to only send particular params through to your model.

--

Fix

If you want to append extra data to each model request - you'll have to use merge:

def app_params
   params.require(:app).permit(:name, :description).merge(user_id: session[:user_id], app_permission_id: app_permission_id) 
end

Upvotes: 1

khaled_gomaa
khaled_gomaa

Reputation: 3422

If you are app_params should always contain user_id and app_permission_id

you should do it this way

def app_params
  params.require(:app).permit( :name,  :description).merge(user_id: session[:user_id], app_permission_id: app_permission_id)
end

Else if it should not contain this all the time

you should do it this way

app_params.merge(user_id: session[:user_id], app_permission_id: app_permission_id) #as mentioned by Vapire in his answer

Upvotes: 6

Vapire
Vapire

Reputation: 4588

Yes, this should be possible with merge

def create
  @app = App.new(app_params.merge(user_id: session[:user_id], app_permission_id: app_permission_id))
end

Of course you'd need virtual attributes user_id and app_permission_id in your model.

Also see this answer.

Upvotes: 1

Related Questions