Undefined method error when using simple_form (newbie) - ruby-on-rails

I've got the following simple_form:
= simple_form_for instance do |f|
= f.input :update_resolution, collection: 1..10
= f.button :submit
It throws the error:
undefined method `update_resolution' for #<Instance:0x007f0c07329640>
In instances_controller.rb I have:
def update_resolution
render nothing: true, status: 200, content_type: 'text/html'
end
And I'm not 100% sure what's best to put in routes.rb.
Goal: I'm trying make an auto-submitting dropdown to allow the user to run update_resolution with certain params.
Questions:
Why does it throw this error & how can I fix it?
What is the preferred routes.rb strategy?

This can be achieved with a model less simple_form. Look at the following code:
<%= simple_form_for :user, url: users_path do |f| %>
<%= f.input :name, as: :string %>
...
<% end %>
url: users_path can be changed to the action you want it to post to. In your case update_resolution_instance_path The action will take the params being passed to it and do whatever it needs to do.
I am using something similar to be able to take data from fields and then send an email to the user entered email address.

Related

Search form Couldn't find User with 'id'=

I need to create search form to search for all the cases pt_name of the user
I got this error
Couldn't find User with 'id'=
In cases controller
def index
#user =User.find(params[:id])
#cases=#user.cases
if params[:search]
#search_term = params[:search]
#cases= #user.cases.casesearch_by(#search_term)
end
end
in case model
class Case < ActiveRecord::Base
belongs_to :user
def self.casesearch_by(search_term)
where("LOWER(pt_name) LIKE :search_term OR LOWER(shade) LIKE :search_term",
search_term: "%#{search_term.downcase}%")
end
end
in cases index.html.erb
<%= form_for "",url: cases_path(#user.id), role: "search", method: :get ,class: "navbar-form navbar-right" do %>
<%= text_field_tag :search, #search_term,placeholder: "Search..." %>
<% end %>
The problem is the first line in your controller.
When the form is submitted it's going to cases_path(#user.id) - that's what you specified in your form.
If you're checking with rails routes you'll see that cases_path is actually going to "/cases" (I am assuming you did not overwrite it) and that there isn't any placeholder for an id (like it would be for the show action for example which goes to "/cases/:id".
Now you still specify #user.id in cases_path(#user.id) and then you try to find a user with the id from the params. But if you check your params once you arrived in the controller (with binding.pry or other tools), you will see there is no key :id in the params. You can also check the url it is going to, I believe it will look something like this: "/cases.1".
You can solve that by changing the path to
cases_path(user_id: #user.id)
This way you add a new key value pair to the params hash and then in your controller you need to change it accordingly:
#user =User.find(params[:user_id])
You can also add a hidden field into your form in order to pass along the user id:
<%= form_for "", url: cases_path, role: "search", method: :get, class: "navbar-form navbar-right" do %>
<%= text_field_tag :search, #search_term,placeholder: "Search..." %>
<%= hidden_field_tag :user_id, #user.id %>
<% end %>
And then retrieve it in the controller.
To check your params that you get in the controller action use a gem like pry byebug or just the keyword raise and then inspect the params variable.

Publish method doesn't work properly

I have an Entry model with a boolean column published, which is set to false by default. I wrote the following method in the model:
def self.publish
self.update(published: true)
end
and in my controller I have
def publish
#entry = Entry.find(params[:id]
#entry.publish
redirect_to entries_path
end
(I thought to make it similar to the calling of destroy method in the model). Finally, in my view I have this:
<%= link_to "Publish", entries_path, method: :publish %>
But when I click the link, the request is processed by create method and returns me the following error:
ActionController::ParameterMissing in Multiflora::EntriesController#create
param is missing or the value is empty: entry
The method is wrong in link_to as per the API so you have to mention one of valid Http methods (patch preferred in your case) , and then edit your route.rb file to transfer this patch request to your specified function like this:
patch'/entries/publish', to: 'entries#publish'
then change the "entries_path" to "entry_path"
so link code should look like this:
<%= link_to "Publish", entry_path, method: :patch%>
First thing, there is no HTTP method called :publish it should be :put or :patch
Second you need to pass id as parameter
<%= link_to "Publish", publish_entry_path(#entry) %>
Also you will need to add route for publish action
resources :events do
member do
put :publish
end
end
publish method should be instance method
def publish
self.update(published: true)
end
Thanks for all the answers, I've figured out what was my mistake, but I took a little think and decided to make it much more simple: I just added a checkbox to edit form, that sets :published attribute of entry true. Here it is:
<%=form_for(#entry, as: :entry, url: content_entry_path(#entry)) do |f| %>
# ...
<p>
<%= f.label "Publish" %> <br />
<%= f.hidden_field :published, value: '' %>
<%= f.check_box :published, checked: true %>
</p>
<% end %>
Anyways a lot of thanks for your answers! That was my lack of knowledge and I'll remember what have I done wrong

How to use devise-invitable

I just started with Rails and devise and I have a task, allow users to sign up only by invitation of existing user. I choose devise-invitable gem and got stuck with a bit unclear documentation. I have this code:
def invitationForm
#nuser = User.new
end
def invite_user
#user = User.invite!({:email => #nuser.email}, current_user)
end
Where invitationForm renders a form:
<%= form_for #nuser, url: {action: "invite_user"} do |f| %>
<%= f.text_field :email %>
<%= f.submit "Invite" %>
<% end %>
After all I`m getting this error:
RuntimeError in User#invite
Showing //invite.html.erb where line #2 raised:
Could not find a valid mapping for nil
What am I doing wrong and what should I do?
I think one of your problems could be here:
<%= form_for #nuser, url: {action: "invite_user"} do |f| %>
Your form was pointing to invite instead of the invite_user method you have created.
Okay, the deal was in the setup, somehow. After creating a new project and starting from scratch all workred fine.

Strong params and action mailer issues

I have tried to create a mailer using the following code:
routes code
resources :listings do
member do
put :lead
end
end
mailer controller code
def lead(listing)
#listing = listing
mail(to: #listing.leadrecepient, subject: "test")
end
standard controller code
def lead
Enquiry.lead(#listing).deliver
end
view
<%= form_for lead_listing_path(#listing), method: :put do |listing| %>
<%= listing.text_field :name %>
<%= listing.submit %>
<% end %>
In the context of a business directory, I want it so that there is a enquiry form on each listing page that when filled out and submitted, the information is sent to the relative listing email.
The problem however is that when I type into the form and click submit, I get the following error:
param is missing or the value is empty: listing
This seems to be because I have it in the "listing" controller which controls the showing and creation of the business listing itself. I therefore have strong params for a new listing which contains all the new listing variables:
def listing_params
params.require(:listing).permit(:fullname, :jobtitle, :email, :franchisename, :leadrecepint, :shortdescription, :longdescription, :website, :branchcount, :scale, :mininvestment, :investmentrange, :category, :hexbg, :logourl, :facebook, :twitter, :linkedin, :googleplus, :approved)
end
How do I go about fixing this? I'm a beginner if I'm honest, could really do with some help to get this mailer working! Thanks.
Strong params are for when you are submitting new resources or modifications to resources. To protect against people adding extra parameters that may circumvent security or other aspects of your application unexpectedly.
If you are adding an action to an existing resource that the user is authorized to access, which this appears to be, you want to just find the object by ID, and use it. So instead of finding it using the params filtered through listing_params, just find it like this in the controller:
def lead
listing = Listing.find(params[:id])
Enquiry.lead(listing).deliver
redirect_to listing
end
And invoke it using a simple link, instead of this:
<%= form_for lead_listing_path(#listing), method: :put do |listing| %>
<%= listing.text_field :name %>
<%= listing.submit %>
<% end %>
Just use this in your view:
= link_to 'Go!', lead_listing_path(#listing), method: :put
Nothing more to it.

rails simple_form fields not related to the model

I have an existing form which is tied to a model named 'Order', but i want to add new form fields that will capture Credit Card info such as name, cc number, etc to be processed on a 3rd party payment gateway.
But since i don't want to save CC info in our database, there are no corresponding columns of that in my order table. And this gives me an error when submitting the form that those Credit card input fields are not 'part' of the order model.
If I understand your answer correctly, what you want to do is explained in the official wiki page here: Create a fake input that does NOT read attributes. You can use a field not related to any real database column by Edward's suggestion, however you don't need to define an attribute in your model if the form field is nothing to do with the model.
In summary, the trick explained in the page is defining a custom input called 'FakeInput' and use it like this:
<%= simple_form_for #user do |f| %>
<%= f.input :agreement, as: :fake %>
....
Do not forget to restart your rails server after adding/modifying a custom input as Fitter Man commented.
UPDATE: Please note that the official wiki page has updated and the sample code on the wiki page is not working for those which use older versions of SimpleForm. Use code below instead if you encounter an error like undefined method merge_wrapper_options for.... I'm using 3.0.1 and this code works well.
class FakeInput < SimpleForm::Inputs::StringInput
# This method only create a basic input without reading any value from object
def input
template.text_field_tag(attribute_name, input_options.delete(:value), input_html_options)
end
end
You can use attr_accessor
class Order < ActiveRecord::Base
attr_accessor :card_number
end
Now you can do Order.first.card_number = '54421542122' or use it in your form or whatever else you need to do.
See here for ruby docs http://www.ruby-doc.org/core-1.9.3/Module.html#method-i-attr_accessor
and here for a useful stackoverflow question What is attr_accessor in Ruby?
Don't get it mixed up with attr_accessible! Difference between attr_accessor and attr_accessible
The best way to handle this is to use simple_fields_for like so:
<%= simple_form_for #user do |f| %>
<%= f.input :first_name %>
<%= f.input :last_name %>
<%= f.input :email %>
<%= simple_fields_for :other do |o| %>
<%= o.input :change_password, as: :boolean, label: 'I want to change my password' %>
<% end %>
<% end %>
In this example, I have added a new field called change_password which is not part of the underlying user model.
The reason this is a good approach, is that it lets you use any of the simple form inputs / wrappers as fields. I don't care for the answer by #baxang, because it doesn't allow you to use different types of inputs. This seems more flexible.
Notice though for this to work, I had to pass :other to simple_fields_for. You can pass any string/symbol as long as there is not a model with that same name.
I.e. unfortunately I can't pass :user, as simple_form would try to instantiate a User model, and we'd get the same error message again...
Also if you're just trying to add something and get it into the params, but leaving it out of the model's hash, you could just do FormTagHelpers. http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html
Example:
<%= simple_form_for resource, :as => resource_name, :url => invitation_path(resource_name), :html => {:method => :post} do |f| %>
<%= devise_error_messages! %>
<% resource.class.invite_key_fields.each do |field| -%>
<%= f.input field %>
<%= hidden_field_tag :object_name, #object.class.name %>
<%= hidden_field_tag :object_id, #object.id %>
<% end -%>
I found a very simple (and somewhat strange) workaround.
Just add the input_html option with any value key inside. E.g:
= simple_form_for #user do |f|
= f.input :whatever, input_html: {value: ''}
Tested simple_from versions: 3.2.1, 3.5.1

Resources