Rails: Using Strong Params as keyword parameters - ruby-on-rails

Let's say I have a User Model with a class method create_with_info. Currently if I want to password the params into the method using keyword parameters, It will be something like this.
# user_controller.rb
def create_with_info
User.create_with_info(**user_info_params)
end
private
def user_info_params
params.require([:name, :age, :email])
params.permit(:name, :age, :email).to_h.symbolize_keys
end
# user.rb
def self.create_with_info(name:, age:, email:)
# do something
end
I'm not sure is it the correct way to use keyword parameters in controller or is there a better way to handle? using to_h.symbolize_keys is annoying for me.

Related

Whitelist Parameters in Controller without a Model

I would like to whitelist a parameter from my params. I have a controller ElectiveRecommendationsController that isn't tied to any Model.
How do I whitelist my :electives? I tried the following, but it didn't work.
def permitted_params
params.permit(:electives)
end
The error I am getting:
You need to specify that electives is a Hash. You'll want this
def permitted_params
params.permit(electives: {})
end

Overwrite permited_params if rails controller has been inherited

Here an example:
class Base<ApplicationController
private
def permited_params
params.require(:object_name).permit(:name, :description)
end
end
class Post<Base
private
def permited_params
params.require(:post).permit(:name, :description, :owner)
end
end
I'm getting an error ActiveModel::ForbiddenAttributesError when call action create. How I can overwrite this permited_params
Params, in general, have a good reason to exist and make sure that not everything can be saved into your database. However, if you want to permit all params you can call
params.require(:post).permit!
In case you just want to change the params you can change the attribute names.
params.require(:post).permit(:name, :description, :some_you_want, some_more ) etc.
In general, you should add all params you want to save into the list of permitted params. So you make sure that all the attributes you want to save will be stored and no more. You can have permitted_params in every controller. You do not need to call it permitted params. For instance you can call it like this in your posts_controller:
def create
#post = Post.new(post_params)
#.... your code
end
private
def post_params
params.require(:post).permit(:name, :description, :owner)
end
This also works for inherited controllers.
Instead of params.require(:post).permit(...
you can use whatever params you want, like params.require(:reply).permit(...
The required param will throw an error if it is not available. So you need to make sure it exists for example by
#post = Post.new
Other params are optional and will not cause an error by default.

How to do strong parameters with an array of objects

If I have a user
def user_params
params.require(:user).permit(:name, :age)
end
I got that down. I want to batch create users. So a user can fill out a list (theoretically endless) of users, they would come in as:
[{name: "name", age: 12},{name: "name", age: 22},{name: "name", age: 32}]
Question is, how do I use strong parameters for that? I know that I can just loop through the array and create the records, I get that. My understanding is that strong params are a generally good idea, safety wise.
What are strong params protecting me from? What would I be opening myself up to here, if I just looped over the array of users? How can I do it properly, either with strong params, or an alternate method?
The entire point of strong parameters (introduce in rails 4) with the goal of protecting applications from mass assignment vulnerabilities. Like for example, lets say you had a User model and it had a admin attribute. If you were using mass assignment in theory someone could slip in a value for the admin attribute if you did not filter it out some how; see below
class UserController < ApplicationController
def create
#{name: 'Joe', score: 7, title: 'Mr', admin: true} params hash
User.create(params)
end
end
Now if some how a user of your app passed in these values they just made themselves and admin and can do as they please. So thats why you would use strong params to do this.
class UserController < ApplicationController
def create
User.create(user_params)
end
def user_params
params.require(:name).permit(:title, :score) #noticed admin is not allowed
end
end
Now to create multiple records with strong params you could do this
class UserController < ApplicationController
def create
user_params[:users].each do |u|
User.create(u)
end
end
def user_params
params.permit(:users, array: [:name, :age])
end
end

Rails 4 Strong parameters for associated model

I do have My users model in Rails4 application and I have Defined
def user_params
params.require(:user).permit(:email)
end
but I am also storing users address in a separate address table and I am filling up email and address both from a single form so how do I add address parameters as well in users strong parameters permit method.
Like so:
def user_params
params.require(:user).permit(:email, address: [:address_attribute])
end
Take a look at THIS post, I think it is pretty good at explaining strong parameters.
Strong parameters should look like this:
def user_params
params.require(:user).permit(:email, addresses_attributes: [:field1, :field2,..])
end
And also make sure that
user.rb
accepts_nested_attributes_for :addresses

How to access params[] when using a callback on model

I'm using the callback before_update to call a function on model which set the checkbox value on my variable.
The problem is the checkbox value which is on params[:mail_checker_issue] isn't accessible on the model layer.
The question is: How to access this params using the callback before_update ? Below my code:
module IssueSetChecketIssuePatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
before_save :before_mail_checker
end
end
end
module InstanceMethods
require_dependency 'issue'
def before_mail_checker
self.set_mail_checker_issue(params[:mail_checker_issue])
end
def set_mail_checker_issue(mail)
#mail_checker = mail
end
def get_mail_checker_issue
#mail_checker
end
end
Rails.configuration.to_prepare do
Issue.send(:include, IssueSetChecketIssuePatch)
end
params are a controller concern and are wholly separate from models. Consider what should happen if you tried to save that model from a console, for example.
You need to pass the param to the model after you instantiate it from your controller, then check the value set on the model in your before_save callback.
It's also worth noting that your code is somewhat un-Rubyish (and really, looks a lot like Java!) - you could get the same effect by just defining an attr on the model.
Rails.configuration.to_prepare do
require_dependency 'issue'
class Issue
attr_accessor :mail_checker_issue
end
end
Then, once you have an issue:
# Controller code
#issue = Issue.find(params[:id])
#issue.mail_checker_issue = params[:mail_checker_issue]
You don't, models don't know about controllers or params hash.
You should include this logic at your controller instead of forcing it in a callback.

Resources