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.
Related
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
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.
I apologize if this is a silly but I have no idea what the following piece of code does
private
# Use callbacks to share common setup or constraints between actions.
def set_article
#article = Article.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def article_params
params.require(:article).permit(:title, :post, :user_id)
end
end
I'm new to rails and I have gotten a fairly good idea of MVC and how it all connects, but I just can't wrap my head around the code above found in the controller files. What's a callback and why would I use one? What is Article.find(params[:id]) doing? What does .permit do in this case? Does it mean that it'll only accept the title, post & user_id parameters and not anything else? And on top of all, why are both the methods private? Thanks in advance!
Callbacks are methods that are called at some points of object's lifecycle. set_article is a callback, because it is called before particular controller actions(usually listed on top of the file). The reason for this is that you need to find an article from the database and assign it to an instance variable in all those actions. This method is meant to keep the code DRY(Do not Repeat Yourself), because if you don't have a private method for this, you would have to copy/paste the line inside the method for each controller action. That is fine as long as you don't need to change it EVER. That is why it is good practice to use callbacks for these kinds of methods.
As mentioned before #article = Article.find(params[:id]) finds an article in the database with a particular ID and assigns it to an instance variable, so you can later render it in a view (using, say, #article.name etc).
What does article_params method do? It takes ALL the params that are passed to the request. then in checks for the construction of the params. In this case params.require(:article).permit(:title, :post, :user_id) it is waiting for params that look like article: { title: "smth", param2: "val2" } etc. That is what .require(:article) does. What permit does, is drop all other params except the ones you have whitelisted.
An example:
def article_params
params.require(:article).permit(:title, :post, :user_id)
end
And let's say a hacker is trying to change forbidden attributes and sends a request like this article: { title: "smth", post: "Hacked", user_id: 1, admin_id: 1(hackers user_id) }
If you do Article.find(params[:id]).update_attributes(params[:article]) it would try to write to the database ALLL the params that have been passed.
If you have the article_params method and you use that instead of raw params: Article.find(params[:id]).update_attributes(article_params)
It will automatically DROP all non-whitelisted params, meaning that article_params will only contain article: { title: "smth", post: "Hacked", user_id: 1}
I hope This is clear now.
Private methods In general private methods are methods that you cannot call outside the object itself. For example if Article has a private method write You cannot do:
article = Article.new
article.write
But if You use the same method when defining some public method for Article
class Article
def needs_write
#Do other stuff
write
end
private
def write
puts "private"
end
end
Then calling article.needs_write would work, and would also call the write method.
It is a bit tricky to understand at first... + to make you more confused - you can, actually, call a private method directly on object via send method, but you shouldn't worry about that at first
these actions are private because we dont want to access these actions outside the class.
def set_article
#article = Article.find(params[:id])
end
this action runs before show and edit you can see at top before_action
it is same as
def show
#article = Article.find(params[:id])
end
we use same thing in edit and show. so we dont want to repeat same thing agian and again. so we put it in an action.
def article_params
params.require(:article).permit(:title, :post, :user_id)
end
this action is accept strong parameters. only these parameter will allow to store in databse
I have a rails 4 app.
When creating permitted params in a controller where there is a belongs_to association with another model, do you need to include the foreign key in the permitted params, so that it can be updated when the record is saved, or is that automatic?
It's NOT automatic.
In Rails 4, you have to permit the attribute in order to be able to mass assign its value. The foreign key of the other model is an attribute of your current model that you're trying to update. Without permitting that, you can't update it's value.
The foreign key is not automatic, the associated object is:
This means the following is true:
#app/controllers/your_controller.rb
class YourController < ApplicationController
def create
#item = Item.new new_params
#associated = Associated.find x
#item.associated = #associated #-> this always works & will save
#item.save
end
private
def new_params
params.require(:item).permit(:name, :etc) #-> foreign_key would have to be explicitly defined here if associated_id was passed from a form
end
end
This should give you some perspective on what you can do with your objects.
Update
If you want to assign a post to the current user each time, you'd be able to use the following:
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
def create
#post = Post.new post_params
#post.user = current_user # -> however you identify the user
#post.save
end
end
I am working on an ROR application and i would like retain form values after the form reloads on some error from the server side so that the user doesn't have to go through filling the form again.
This is standard functionality, which is enabled with use of an #instance variable. This allows you to send data to a Ruby class (controller) and process the returned data in a single instance
You'd do it like this:
#app/controllers/posts_controller.rb
def new
#post = Post.new #-> notice instance variable
end
def create
#post = Post.new(post_params)
#post.save
end
private
def post_params
params.require(:post).permit(:title, :body)
end
This enables you to maintain the instance of your newly created ActiveRecord object. It means each time you can't submit your form, you'll receive errors with the previously inputted data