I have an issue when submitting a form.
I have two models, :service and :booking. For a service, there is a button:
<%= link_to "Book Now", new_booking_path(service_id: #service.id) %>
When this button is clicked it takes the user to the _form.html.erb where they can book the service. This is the simplified booking form:
<%= simple_form_for (#booking) do |f| %>
<%= f.label "Booking Date" %><br>
<%= f.text_field :date %>
<%= f.text_field :time, :id => "timepicker" %>
<%= f.input :address, label: "Address" %>
<%= f.input :postcode, label: "Postcode" %>
<%= f.input :suburb, label: "Suburb" %>
<%= f.input :servicetitle, :input_html => { :value => #service.title } %>
<%= f.input :serviceprice, :input_html => { :value => #service.price } %>
<%= f.input :servicetime, :input_html => { :value => #service.time } %>
<%= f.button :submit %>
<% end %>
As you can see, I have three fields, :servicetitle, :serviceprice and :servicetime.
These fields get their input values from the #service.id value passed through the link_to button. I am able to access the records like #service.title using this instance variable in the bookings_controller:
#service = Service.find_by_id(params[:service_id])
The problem I am having is that if one of the field validation fails (say the :date field), then the user gets redirected back to the _form.html.erb and I get the error
NoMethodError in Bookings#create
undefined method title
I would also get the errors:
undefined method price
and:
undefined method time
I think this is because Rails doesn't have access to the #service instance variable anymore?
How am I able to fix this when a validation fails?
Edit:
Create method in bookings controller:
def create
#booking = current_user.bookings.build(bookings_params)
if #booking.save
BookingMailer.form_confirmation(#booking).deliver
redirect_to #booking
else
render 'new'
end
end
I am pretty sure this is down to the fact that in your create method you have not assigned anything to the #service variable, in your new method you are instantiating the #service variable (at least I assume you are as you are not getting an error when you go to the 'action'), but you are not doing it in the create action.
When you go to the create action, the whole request cycle starts from scratch, meaning anything you did in the 'new' action is gone.
When you have an error, your create action goes to the else block and runs render 'new' which renders the new.html.erb template from scratch, if you are rendering a template with an #service variable, then you will need to define that variable in the action before you render the template. eg #service = Service.new or #service = Service.find(params[:service_id]). Otherwise, your template is calling the title price and time methods on a nil object.
You haven't passed the service id again to create method so probably it won't be getting the params[:service_id] in create.
Add a hidden field in form with the service_id and then check.
<%= hidden_field_tag(:service_id,#service.id) %>
Related
In the first controller, I set my session variables:
def show
#item = Item.find(params[:id])
session[:item_id] = #item.id
session[:amount] = params[:amount]
end
My view sets the amount with a form_tag:
<%= form_tag checkout_transaction_path, method: :get do %>
<%= label_tag :amount %>
<%= text_field :amount, placeholder: "Total bid amount", autofocus: true %>
<%= submit_tag "submit" %>
<% end %>
The parameters that get sent with this form look like this:
Parameters: {"utf8"=>"✓", "amount"=>{"{:placeholder=>\"Total bid amount\", :autofocus=>true}"=>"1111"}, "commit"=>"Confirm offer", "id"=>"1"}
The second controller tries to assign the session variable to an instance variable.
def checkout
#item = session[:item]
#amount = session[:amount]
end
However, only #item is working. I try to multiply #amount * 0.10 but get this error: undefined method '*' for nil:NilClass
What causes that error? The submit params says it's being submitted, but maybe something is up with the way I try to retrieve it? session[:item_id] goes through perfectly.
You have issue here:
Parameters: {"utf8"=>"✓", "amount"=>{"{:placeholder=>\"Total bid amount\", :autofocus=>true}"=>"1111"}, "commit"=>"Confirm offer", "id"=>"sam-lipp-abandonment"}
In your parameters, you send amount parameters but in amount, you send HTML form "amount"=>{"{:placeholder=>\"Total bid amount\", :autofocus=>true}"=>"1111"}, but should send only value what you set in the amount form, and your amount parameters should looks like this example! "amount"=>"1"
So this means that your form doesn't work correctly!
Try please replace your form on this one, and in a controller, you will get amount!
<%= form_for #new_item, url: checkout_transaction_path do |f| %>
<%= f.label :amount %>
<%= f.text_field :amount, placeholder: "Total bid amount", autofocus: true %>
<%= submit_tag "submit" %>
<% end %>
OR the same code for form_tag
<%= form_tag checkout_transaction_path do %>
<%= label_tag :amount %>
<%= text_field_tag :amount, placeholder: "Total bid amount", autofocus: true %>
<%= submit_tag "Submit Post" %>
<% end %>
The problem in your form can be here:
you wrote text_field instead text_field_tag
Also for form_for form, you need to add in the controller in a method with variable what you will use in your form, for example, I'm using variable #new_item where from you call this form, something like this
def new
#new_item = Item.new
end
In my RoR application I am allowing users to select contacts that they want to send an email to. The users select these contacts via checkboxes on the form. I am trying to add in search functionality so that a user can search by first name and only check boxes with contacts that match that search appear.
To do this I am trying to use this code on the view:
<div class="form-group">
<label>From Email Address</label></br>
<% #useraccounts.each do |useraccount| %>
<%= f.radio_button :account_id, useraccount.account_id, :checked => false %>
<%= f.label :account_id, useraccount.account.email, :value => "true" %><br>
<% end %>
</div>
<div class="form-group">
<%= form_tag '/emails/contact_search', :method => 'get' do %>
<p>
<%= text_field_tag :search_string, params[:search_string], :placeholder => "Search by firstname" %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
<label>Contacts</label></br>
<%= f.collection_check_boxes :contact_ids, #contacts, :id, :fullname %>
</div>
Where the #contacts instance variable holds the contacts returned from the search in the controller.
When a user clicks the search button, the below controller action should be invoked.
def contact_search
#email.recipients.build
#useraccounts = Useraccount.where(user_id: session[:user_id])
#contacts = Contact.contacts_search(params[:search_string])
if #contacts.empty?
flash.now[:alert] = "There are no contacts with that name."
#contacts = Contact.all
end
render :action => "new"
end
This controller action uses the contact_search method, which is in the Contact.rb model:
def self.contact_search(search_string)
self.where("firstname LIKE ?", search_string)
end
I also have the contact_search in the routes:
post 'emails/contact_search', :to => 'emails#contact_search'
get 'emails/contact_search', :to => 'emails#contact_search'
But for some reason, when a user clicks search they get a NoMethodError in Emails#create undefined method 'each' for nil:NilClass on the form. The error is as pictured.
I cannot work out why this isn't working, can someone please help?
By the erb, I guess you have a form_tag inside a form_for block... You can't do that
When you hit Submit, the action is going to the first form action... that probably is a create
It's better move your form_tag to outside your previous form block...
Seems your Modal name (Useraccount) is incorrect this must be UserAccount.
Also Please note
When we use where query with ActiveRecord modal we never get NIL object unless we have wrong Modal name.
Im trying to design a shopping cart. i.e a customer shopping online adds a product to their trolley.
I want to go straight to create action from my new action without going to new.html.erb with pre-set values in my params
Here is what I have so far:
#trolley_id += 1
redirect_to :controller => 'trolleys', :action => 'create', :id => #trolley_id, :something => 'else', method: :post
This redirects me to my index action
To do this with javascript templates, it would look like this:
view
= form_form Trolley.new, remote: true do
-# form goes here
The remote true will submit it as javascript, which will try to render a javascript template.
Your create action can either render :create or let Rails render your template automatically. Since it came in as a javascript request, Rails will render the template with format js.
trolleys/create.js.erb
var html = "<%= j render 'trolley_row', trolley: #trolley %>
$('table.trolleys body').append(html);
I managed to resolve my problem. I created a form in my Product_controller#show that will go straight to my Trolley_controller#create and create an entry in my Trolleys table
<%= simple_form_for [#product, #trolley] do |f| %>
<%= f.input :quantity, collection: 1..12, prompt: "select quantity" %>
<%= f.input :product_id, :as => :hidden %>
<%= f.input :user_id, :as => :hidden %>
<%= f.button :submit, "Add to Basket" %>
<% end %>
I've got a Rails app that has two main views: an overview and a sequenced view. The user can enter data in either view. I use the same form helper for both views, but I want the redirect_to from the create action to respect the user's context. So I pass a hidden_field_tag called 'track'.
I can't seem to access the value of 'track' inside my controller.
Here's the form:
<%= form_for([#mission, #mission.stickies.build]) do |f| %>
<div class="field">
<%= f.text_field :name, :size => 60 %>
<%= f.hidden_field :kind, :value => kind %>
<%= hidden_field_tag :track, :value => track %>
<class="actions">
<br><%= f.submit "Add to " + kind.pluralize.capitalize %>
</div>
<% end %>
And here's where I call it in one of the views:
<%= render :partial => "stickies/form" , :locals => { :kind => "driver", :track => 'main' } %>
Here's the parameters dump (from a different call):
{"utf8"=>"✓",
"authenticity_token"=>"N3IXwNQosOfxw1ZcpfFPOLPKzHbvNyaBhAiP3ftT9GY=",
"sticky"=>{"name"=>"Tesssksjd argghh.",
"kind"=>"success"},
"track"=>"{:value=>\"sequence\"}",
"commit"=>"Add to Successes",
"mission_id"=>"32"}
And here's the relevant code in my create controller:
if params[:track][:value] == "main" then
redirect_to mission_path(#mission) + '#' + #sticky.kind.pluralize
elsif params[:track][:value] == "sequence" then
redirect_to mission_stickies_path(#mission, :kind => #sticky.kind)
end
I can't seem to find the syntax, or comparator, or whatever I need to access the value represented by "track"=>"{:value=>\"sequence\"}".
Any help or pointers would be greatly appreciated. I'm new to Rails and Ruby, this is my first app.
Don't write it with the :value => track, rather do:
<%= hidden_field_tag :track, track %>
and access it with params[:track]
Forgive me for asking what i believe is quite an in depth challenge (well for me at the moment anyway)
I have a small app that allows users to check in, check out and hopefully receive emails when a book has been checked back in by registering their interest via a remind me button
So far I have setup actionmailer (basic setup)
class ReminderMailer < ActionMailer::Base
default from: "email address"
def remind_email(book)
#book = book
#url = "http://localhost:3000"
mail(:to => #book.user.email, :subject => "Book Reminder")
end
I have all the config in place to send the emails as I am already doing that through devise.
I have also created the mailer templates. It is the logic I am stuck with.
So when a User checks a book out i pass this back to the model
<%= form_for #book do |f| %>
<%= f.label :checked_out, "Check Book Out?" %>
<%= f.check_box :checked_out, {}, true %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.hidden_field :checked_out, :value => true %>
<%= f.submit 'Checkout' %>
<% end %>
Check In
<%= form_for #book do |f| %>
<%= f.label :checked_out, "Check Book Back In" %>
<%= f.check_box :checked_out, {checked: false}, false %>
<%= f.hidden_field :user_id, :value => nil %>
<%= f.hidden_field :checked_out, :value => false %>
<%= f.submit 'Check In' %>
<% end %>
Register Interest
<%= form_for #book do |f| %>
<%= f.label :remind_me, "let Me know when book back in" %>
<%= f.check_box :remind_me, {checked: false}, false %>
<%= f.hidden_field :remind_me, :value => current_user.id %>
<%= f.submit 'Remind Me' %>
<% end %>
So my thinking is that when you register your interest your user id gets placed into the remind_me column, and what i want to achieve is that when the checked_out field is false and book.user_id is back to nil I would like the email to send the the user whos user_id is in the remind_me column
Am i thinking about this in the correct way?
if anyone can help it would be appreciated so that i can learn from this and then keep practicing it until I understand what is going on
There are 2 ways to answer:
The first one, don't use a form to check in a book and just call a method. For example: You replace your form with a link which call a new method in your controller:
<%= link_to "check in", check_in_book_path(#book.id) %>
In your books_controller you call a model method which check in the book:
def check_in
#book = Book.find params[:id]
#book.check_in!
redirect_to book_path(#book)
end
In your book model:
def check_in!
self.user = nil
self.checked_out = false
if self.save
RemindMailer.remind_mail(self).deliver
end
end
Don't forget to add the route for your new controller method.
The second way, if you keep your form, is shorter but more complicated. You need to add a callback to your model which will verify if the data changed. For example, in you book model:
after_save :send_mail_if_check_in
def send_mail_if_check_in
if !self.checked_out && self.changes[:user_id] && self.user.nil?
RemindMailer.remind_mail(self).deliver
end
end
I prefer the first solution because it seems to be a state machine which is more maintenable.
I hope this help