After renaming a model, why do my create and update functions fail? - ruby-on-rails

I renamed one of my models and its associated table name, controller, view folder, and references of the old name throughout all files in the app. The app runs fine except I'm now unable to create or update Actions (new name) because of an error related to params. Here is the error received when creating a new Action:
undefined method `permit' for "create":String Did you mean? print
Here are the params shown with this error:
Parameters:
{"utf8"=>"✓", "authenticity_token"=>"[removed]", "commit"=>"Create This Campaign"}
I manually replaced the token with [removed] here.
I receive the same error when trying to update an Action:
undefined method `permit' for "update":String Did you mean? print
And here are the parameters shown with this update error:
Parameters:
{"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"[removed]", "commit"=>"Submit", "id"=>"50"}
Before I renamed everything, these errors did not appear. Any idea why this is occurring? It looks like my app is passing a string (instead of a hash) to params.require(:action).permit, but I'm not sure why it would be doing that.

You shouldn't use action as a resource name in Rails. The action parameter in params is always set to the name of the action being invoked, meaning you cannot use params[:action] to post data back to your server.
In a controller's update action, params[:action] will always be the string "update", hence the error you're getting about permit not being defined on the string "update".

Related

Rails 5 Params / Strong Params issue

I have a RESTful API (ActionController::API) service that accepts a list of params. The RESTful service takes a JSON body request (with Content-Type of application/json). When I debug the controller/action (right after the action def) and take a peak at the params list, it appears as follows:
<ActionController::Parameters {"given_name"=>"Mark", "subdomain"=>"development", "controller"=>"user", "action"=>"create", "user"=>{"given_name"=>"Mark"}} permitted: false>
EDIT
All the request has in it (when it is passed to the controller/action -- using POSTman):
{"given_name":"Mark"}
Notice that the object contains the given_name params twice. Is this normal behavior? I did not pass a "user" object (json object) to the controller/action? What is the permitted flag?
When I try to use (right now I'm just testing RESTful call and assigning any values that the user object will except... no validations have been programmed yet):
user = User.new(params)
I get the error:
#<ActiveModel::ForbiddenAttributesError: ActiveModel::ForbiddenAttributesError>
So, I've looked everywhere for the reasoning behind this (why is there a "user" key in the params list? What is the purpose of the permitted flag? Why am I getting an error when I try to assign params)?
EDIT
After doing some testing, I change the controller name from "user_controller" to "tester_controller" and setup the routes to point to the renamed controller.
It seems the "user" object in the params list above has changed to "tester". So why does the param list contain an "object" with all the passed params with the name of the controller? If that's the case, why is it needed?
Any help would be greatly appreciated.
By default Rails in API mode wraps JSON request parameters into a hash guessing its name from controller class. That's why changing the controller from User to Tester changes "object" name. You can read details here.
So if you don't need this "object" in your params just remove :json from :format array in config\initializers\wrap_parameters.rb. Or you can use fine-grained control at the controller level as described above.
You need to specify which attributes are acceptable for mass-assignment in your controller.
def create
#user = User.new(params.require(:user).permit(:given_name))
end
This prevents malicious users from making request posts that alter attributes internal to your application, like role in the case of a user object.
As mentioned above, a better explanation can be found in the guide referring to strong parameters.
You can't pass params to constructor, because params always contain :action and :controller keys. Attributes for new objects should be put in hash under key that identify model you want to create e.g. :user. I suggest you to consult rails guides, especially chapter 7 of "Form Helpers" guide.
If you want to learn more about strong parameters there is a chapter in rails guides for that too :)

How param works in rails views

I have an old app running in rails 2.3.5
In customizing, I stuck when i find a param keyword being used in views
i.e in views I can see stuffs like
unless params[:fee_collection].nil?
can someone explain to me in what context is param keyword used in rail views rather than controllers
params is a hash that contains parameters sent with the HTTP request.
You can access to this object as well from your controller or from a view. Although, the convention is to access to an instance variable (defined in your controller, e.g : #fee_collection = params[:fee_collection]) from your view.
The params variable stores a hash which contains the http parameters received in the request to this route (controller#action)
If you have a UserController with the show method, you should receive the param[:id] to identify the resource you're looking for.
If you want to send parameters, it would be either via url in a GET or a data payload on a POST request, on the most common cases.

Rails: Form Tag Skipping Controller Action

I cannot explain why, but somehow my form_tag form is skipping streight to my view and completely bypassing my controller action.
This is my form_tag:
<%=form_tag url_for(:controller=>"orders", :action=>"finalize_order"), :method=>'post' do%>
<%=hidden_field_tag "cc_id_selection"%>
<%=hidden_field_tag "address_id_selection"%>
<%=submit_tag "Checkout", :class=>"btn btn-primary"%>
<%end%>
And here is my controller action:
def finalize_order
#selected_user_card_id = UserCard.find(params[:cc_id_selection])
begin #in case they chose pickup
#selected_address = Address.find(params[:address_id_selection])
rescue
#selected_address = params[:address_id_selection] #we can add options besides pickup if we'd like
end
end
This is what is logged in my console (with some ip stuff taken out) I tried putting a trace in the controller and don't see any sign of it:
Started POST "/finalize_order" Processing by OrdersController#finalize_order as HTML
I see at the bottom of the error page that the two params were successfully posted. Yet when I submit I get error in the next view indicating no param was instantiated in the controller. Even stranger, when I comment out the action I get the same exact results! I even tried using a route, anf get the same results. It seems I am completely skipping the action and going streight to the view. What might cause this bug?
I suspect you've accidentally made your finalize_order method private in your controller. If it's a private method, it won't be called, and the view will be rendered directly. This is a little-known feature of Rails - the action doesn't actually have to exist.
If the method is private, (the private keyword will be above it in the controller somewhere) then move the action to above the keyword to make it public.
Along the lines of what sevenseacat suggested, but the actual problem is that I accidentally had two finalize_order methods. I guess rails couldn't decide which one to run, so it ran neither.

Why can't I use a param called "action"?

Is "action" as a input field name forbidden? Because everything works except the assignment of the "action" param.
because action, controller are prohibited words.
Look around debug params
--- !map:ActiveSupport::HashWithIndifferentAccess
action: index
controller: main
so you can't use those params. Because they will be REWRITED AUTOMATICALLY
I would suggest NOT using words like action, name, method as field names as they are all attributes of the form tag and are likely to get confused when the form is posted
I agree with jbeynon, I would also say anything that has to do with CRUD(Create, Read, Update, Delete) is protected also.
I don't see why this would be invalid. You'd want to avoid conflicting with existing class or method names (e.g. not a good idea to define a method called action on a controller).
everything works except the assignment
of the "action" param.
Does this generate an error? If so, what exactly?

Pylons FormEncode #validate decorator pass parameters into re-render action

I am attempting to use the validate decorator in Pylons with FormEncode and I have encountered an issue. I am attempting to validate a form on a controller action that requires parameters, and if the validation fails, the parameters aren't passed back in when the form is re-rendered. Here's an example.
def question_set(self, id):
c.question_set = meta.Session.query(QuestionSet).filter_by(id=id).first()
c.question_subjects = meta.Session.query(QuestionSubject).order_by(QuestionSubject.name).all()
return render('/derived/admin/question_set.mako')
This is the controller action that contains my form. The form will add questions to an existing question set, which is identified by id. My add question controller action looks like this:
#validate(schema=QuestionForm(), form='question_set', post_only=True)
def add_question(self):
stuff...
Now, if the validation fails FormEncode attempts to redisplay the question_set form, but it does not pass the id parameter back in, so the question set form will not render. Is it possible to pass the id back in with the #validate decorator, or do I need to use a different method to achieve what I am attempting to do?
I think the problem is that add_question() doesn't receive id argument. Try to set up your routing so that add_question() receives it not only in POST vars but also as argument and see if it fixes the issue.
I had a similar issue. I adjusted my route to include the id and it worked.

Resources