Undefined method? Controller params in Rails 4 - ruby-on-rails

I am getting the weirdest error I have ever seen, consider the following create method:
def create
post = Post.find_by(id: params[:post_id])
#comment = Comment.new(comment_create_params)
#comment.post_id = post.id #I know this line is useless I have yet to refactor.
controller_save(#comment)
end
From here we have comment_create params which is a private method but is defined as such:
def comment_create_params
params.require(:comment).permit(:author, :comment, :parent_id)
end
Now consider the following params that were passed in:
params => {"author"=>"157685iyutrewe1wq",
"comment"=>"14253647turyerwe",
"action"=>"create",
"controller"=>"api/v1/comments",
"post_id"=>"126"}
Based on this everything looks correct. Running through this function everything should save. Till I get the following error:
NoMethodError: undefined method `permit' for "14253647turyerwe":String
I have no idea what this means - I think its trying to treat: "14253647turyerwe" as a method which is a string? not sure....

Params
params.require(:comment).permit(:author, :comment, :parent_id)
This will basically look for a hash which inherits from a comment key, like this:
{"comment" =>
{
"id" => "5",
"name" => "test"
}
}
So when you use the require method, you're basically saying "we need this top-level hash key", to which Rails will then go into the nested hash & use the permit method to locate the other attributes, as shown above.
The problem you have is this:
params => {"author"=>"157685iyutrewe1wq",
"comment"=>"14253647turyerwe",
"action"=>"create",
"controller"=>"api/v1/comments",
"post_id"=>"126"}
The problem here is you're calling require on the comment key; which is just a string. To fix this, you'll need to do something like this:
def comment_params
params.permit(:author, :comment, :action)
end
--
Save
Something else you need to consider is the controller_save method. I've never seen this before, and is against convention. Not a problem with this, but means if you get team members on your app, or want to upgrade Rails, it will be a pain to adapt it.
I would definitely use the standard .save method, like this:
#app/controllers/comments_controller.rb
def create
...
#comment.save
end

The Actual issue was that the attribute in the Comment model was also comment, upon changing it (and the migration scripts as well as tests) to comment_text everything worked again :D

Your 'params' are formed definitely not by a rails' form_for. Because it would be looked as params: { comment: { "author"=>"157685iyutrewe1wq", "post_id" => "some_id" } }
And so your params.require(:comment) returns 'String' object with value = "14253647turyerwe" and it really has no any 'permit' method.
So I suggest you to read about forms in rails, what html parameters they are construct while sending form data to a server
UPDATE:
If for some reason you have no mood for using a form_for #model helper, your whatever method of generating of form should produce for each field of that model something like this html:
<input id="comment_author" name="comment[author]" type="text" value="14253647turyerwe"/>
for them moment I suspect you got something like:
<input id="author" name="author" type="text" value="14253647turyerwe"/>

Related

Unpermitted parameter error when adding request parameter while using Administrate

I'm using Administrate v0.11.0 with search_term textbox,
it works totally fine,
and now I want to add a request parameter my_search_condition_flag which is a boolean flag value that affects search condition.
In my index action of controller,
I added the following line, so that requests with this parameter pass the Strong Parameters validation.
params.permit(:search, :my_search_condition_flag)
The rest of the code in index action is simply copied from ApplicationController.rb of Administrate.
When I make a HTTP request with request parameter my_search_condition_flag=1 ,
my index action is processed just fine,
but HTTP response returns following error:
ActionController::UnpermittedParameters in Admin::MyPage#index
Showing /usr/local/bundle/gems/administrate-0.11.0/app/views/administrate/application/_search.html.erb where line #19 raised:
found unpermitted parameter: :my_search_condition_flag
which is raised from rendering method of search_term textbox inside index.html.erb
<% if show_search_bar %>
<%= render(
"search",
search_term: search_term,
resource_name: display_resource_name(page.resource_name)
) %>
<% end %>
I've already tried the following to my Dashboard class, introduced here:
# -- Overwrite the method to add one more to the permit list
def permitted_attributes
super + [:my_search_condition_flag] # -- Adding our now removed field to thepermitted list
end
How can I tell Administrate to permit a parameter which I want to add?
Do I have to use request body instead? (which I don't want)
You were on the right track there. The exception originates at /app/views/administrate/application/_search.html.erb:19, as you mention. If you look there, you'll see it uses the method clear_search_params, which also uses strong_parameters to allow/deny query params. You can override this with a helper of your own. For example:
module Admin
module ApplicationHelper
def clear_search_params
params.except(:search, :page, :my_required_condition_flag).permit(
:per_page, resource_name => %i[order direction]
)
end
end
end
If you do this, you'll get a new, related error. This time from /app/helpers/administrate/application_helper.rb:48. The method there is called sanitized_order_params, and can be overriden similarly:
module Admin
module ApplicationHelper
# ...
def sanitized_order_params(page, current_field_name)
collection_names = page.item_includes + [current_field_name]
association_params = collection_names.map do |assoc_name|
{ assoc_name => %i[order direction page per_page] }
end
params.permit(:search, :my_required_condition_flag, :id, :page, :per_page, association_params)
end
end
end
And with that, you should be clear of errors.
Admittedly, this is not very nice fix. Ideally Administrate should be providing some better way to override this list of allowed search params. Fancy submitting a PR? ;-)

Affecting resulting params set from form_for

Relative newbie here to Ruby on Rails.
Using the standard form_for method in the view for my SomeobjController#new action
= form_for #someobj do |f|
.
.
.
%p.submits
= f.submit "Submit", :class => "submit"
a submission param[] array is produced that contains a hash of #someobj for all the fields set in the form, such that
param[someobj] => { "field1" => "val1", "field2" => "val2", ... }
I would prefer to put a different value, the result of someobj.to_s to param[someobj] for the SomeobjController#create to work with, such that
param[someobj] => "strvalfromtos"
I doubt it's relative, but just in case, the model underlying this #new action is not persistent in the database (i.e., Someobj is not derived from ActiveRecord::Base, though some portions of ActiveModel are included.)
I haven't had luck trying to adjust this until after #create is invoked, but its the submission from #new to #create that I want to amend. It's not clear to me if I should be focusing more on the form_for statement or doing something special in the controller (I'm guessing the form_for is the right focus).
And, yes, this whole thing is probably a bit OCD of me, but the actual fieldnames are long (appropriately for the model) but data needed by #create is very small.
Is there a relatively painless way to do this, assuming that someobj.to_s has already been written?
Many thanks,
Richard
Change
When you submit the form, your controller will receive the params hash, as you've stated (Rails params explained?)
That means you can change any value in the hash that you wish:
def create
#has access to the params hash
params[:owner][:key] = value
end
As the create method receives the hash object, you'll have to change it in here. But because it's a standard hash (which has already been declared), you should be able to alter it as required
Add
If you want to add values to the params hash, you can use the .merge method, like this:
def create
#has access to the params hash
params[:key].merge(user_id: current_user.id)
end

Rails Rating System with strange helper method

there's an issue, that is bothering me.
I'm following this "Ruby on Rails"-Tutorial to implement an ajaxified rating system
http://eighty-b.tumblr.com/post/1569674815/creating-an-ajaxified-star-rating-system-in-rails-3
Die author uses a self written helper method called "rating_ballot" which seems pretty redundant to me, because it checks if a rating has been given yet and otherwise forms a new one with
current_user.ratings.new
But that actually is being done more or less in the ratingscontroller
using this helper method the form looks like this
= form_for(rating_ballot, :html => { :class => 'rating_ballot' }) do |f|
But any other form (for example posting reviews) uses the instance variable instead of a helper method.
I want the form_for tag to look like this
= form_for(#rating, :html => { :class => 'rating_ballot' }) do |f|
but this only works for updating ratings, not creating new ones.
why is this "rating_ballot" so important ?
Take a look on that part
def rating_ballot
if #rating = current_user.ratings.find_by_photo_id(params[:id])
#rating
else
current_user.ratings.new
end
end
It try to find out #rating if exists and create new instance if not exsits
you can do it in you controller for example:
#rating = current_user.ratings.find_by_photo_id(params[:id])
#rating ||= current_user.ratings.new # create instance if did not find existing once
ans then use it in form like you wrote
I'm guessing the value of #rating is nil, which is why using this form for the #create action isn't working. The first argument should be a new object, or an object that represents an existing record, in order to create or update, respectively.
Another alternative way of using the form_for method is to supply a symbol representing the name of the class and also specifying the :url argument according to how your routes are specified. This is only good for creating though since the symbol doesn't represent an existing record.

Type Error in RSpec controller spec

I am having troubles with an RSPec test. The test does a PUT with some objects in the request. The controller which receives the PUT seems to be not getting the correct values
For example, 'put :update, :id => #channel.id, :channel => #channel, :tags => #tag' Then, in the Controller, when I try to use params[:tags] there is an integer in that location. A Gist with the Spec and the controller method is at https://gist.github.com/3715021
This started happening when I upgraded from Rails 3.0.13 to 3.1.8
Any idea what might be happening here and how to resolve it?
I'm assuming that #tag is an object from your Tags model. When you give Rails an object like
`get :action, :foo => foo`
or in a url helper (e.g., foo_path(foo)),
Rails will turn your object into a parameter suitable for use in a url via the #to_param method. You're probably getting an integer because Tag#to_param returns the id of the tag in your db.
It looks like your update action, by contrast, expects params[:tags] to be a hash, presumably generated from a form that includes fields for values like tags[:name].
I can't help much more without knowing more about the relevant code. But I'm guessing what you want to do is change your test to read
put :update, :id => #channel.id, :channel => #channel, :tags => { :name => 'tag' }
or something like that, mimicking the params you'd get by actually submitting the form that PUTs to your update action.
This is difficult to help you because we don't know what you're trying to do. For example, it would be helpful if you showed more of the test (for example, the values you set as your variables) and the specific results of the test.
Anyway, is the #tags variable an arel object? and if so, are you expecting the ID as the value to be passed? If not, then you probably want to specify the attribute referenced in #tags. For example, #tags.name... Or, does #tags reference a hash, itself?

Passing a model attribute to a Rails view using redirect_to

I'm trying to pass a model attribute to a view, after successfully setting it to a new value from inside an action in my controller. But this variable is always nil by the time it gets to the view, so I can't use it to conditionally display stuff. I should add that this attribute is not a field in the database. What am I missing/doing wrong?
Here is the code in my model:
attr_accessor :mode
#getter
def mode
#mode
end
#setter
def mode=(val)
#mode = val
end
...in the controller:
#report.mode = "t"
redirect_to edit_report_path(#report)
...and in my view:
<%= build_report(#report.mode) %>
...but this helper method never gets the variable I just set in the controller. It is nil. What gives? Clearly I'm missing something basic here because this seems like it should be straightforward. Any insight would be greatly appreciated.
Thanks.
edit_report_path generates a URL with the ID of #report in it.
redirect_to essentially creates a whole new request, and goes to that URL. When it gets to edit, all it has is the ID. Usually that's fine - it looks up the object and keeps going, but of course it's not going to have the non-db field you set.
There are a couple ways to fix this. You can use :render instead to get to the edit page - then #report will have the field set.
#report.mode = "t"
render :action => edit and return
Or, you can make mode a database field.
The problem here is in the redirect_to. When you redirect somewhere else all instance variables are lost. So when you set #report.mode = "t" it sets the attribute. But when you redirect that data is lost.
I am assuming the <%= build_report(#report.mode) %> is in edit_report.html.erb and the code from when you set 'mode' is not in the edit action. If this is the case you may be able to pass the report.mode to the edit action in the url like so:
build_report(#report.mode, :mode => "t")
The problem is the redirect_to; you're returning a response to the client that causes it to redo the request with a different url. In that second request the mode isn't set because you didn't save it before wrapping up the first request.

Resources