Ruby on Rails 3, I have an edit page with two select_tag submissions. One has users that have the attribute :attend = "Yes" and the other has users that have the attribute :attend = "No" or nil. I am trying to get the select_tag submissions to create or update the Certificate table for the user. As of now I know it is POSTing the user id and name. I do not know how to get the controller or model to take the user id and create or update with the :attend attribute value of "Yes" or "No". The app will create a new record with the correct user id but not with :attend since it is not in my select_tag submission.
Here is my edit:
<%= form_for #untrained do |f| %>
<p> Trained Users </p>
<%= select_tag "certificate[user_id]", options_for_select(#current_trained.collect{|x| [x.name, x.id]}), {:multiple => :multiple} %>
<%= f.submit "Un-Train", class: "btn btn-large btn-primary" %>
<% end %>
<%= form_for #trained do |f| %>
<p> Non-Trained Users </p>
<%= select_tag "certificate[user_id]", options_for_select(#non_trained.collect{|x| [x.name, x.id]}), {:multiple => :multiple} %>
<%= f.submit "Trained", class: "btn btn-large btn-primary" %>
<% end %>
Here is my controller:
#trained = Certificate.new(params[:certificate])
#untrained = Certificate.update(params[:user_id])
Here is my model:
attr_accessible :attend, :pass, :user_id
belongs_to :user
validates :user_id, presence: true
How do you set the controller to create or update a new record with :attend as "Yes"?
How do you update the record with :attend as "No"?
Thank you
Have u tried in the controller after
if #trained.save
put
#trained.update_attributes(attend: "yes")
or no depending on the type u want.
Also have a look at this for the create/update method in rails.
create_or_update method in rails
Related
I've created a form with some radio buttons and had to interpolate the appointment.id into the radio button and the label. However, Rails is throwing the error:
undefined method cancel_3 for Appointment.
So I have tried to make a method in the Appointment model to solve this by using define_method (see below). However as this is in the model, I'm unable to use the instance of appointment here.
Is there any way I can make this work?
define_method "cancel_#{appointment.id}" do
# ...
end
<%= f.radio_button "cancel_#{appointment.id}", :true %>
<%= f.label "cancel_#{appointment.id}_true", "Yes", class: "modal-options cancel" %>
<%= simple_form_for :appointment, url: delete_admin_appointment_path(appointment) do |f| %>
update your form with
<%= simple_form_for #appointment, url: delete_admin_appointment_path(#appointment) do |f| %>
and in your controller
def new
#apointment = Apointment.new
end
and radio button with
<%= f.radio_button "cancel_#{#appointment.id}", :true %>
<%= f.label "cancel_#{#appointment.id}_true", "Yes", class: "modal-options cancel" %>
I am having trouble passing a parameter defined in a hidden_field of a simple_form to a create action. In our app, a User has many bets through memberships. Membership columns include bet_id, user_id, accepted:boolean, and against:boolean. The against column of Membership indicates whether the user is betting against or betting with the bet. In the view for a particular bet, a user who does not have a membership can choose "Agree" or "Against", which will create a new membership with the appropriate accepted:boolean. Here are the forms found the the bet show page.
<%= simple_form_for([#bet, #bet.memberships.build]) do |f| %>
<%= f.hidden_field :against, against: false %>
<%= f.button :submit, "Agree!" %>
<% end %>
<%= simple_form_for([#bet, #bet.memberships.build]) do |f| %>
<%= f.hidden_field :against, against: true %>
<%= f.button :submit, "Against!" %>
<% end %>
Here is the attempted create action
def create
#membership = current_user.memberships.build(bet_id: params[:bet_id], against: params[:against], accepted: :false)
redirect_to :back
end
This currently just leaves the accepted value as nil. Any help would really be appreciated! Thanks
Try using this:
<%= f.hidden_field :against, value: false %>
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
I have 2 models called worequest and status.
worequests has_many statuses and status belongs to worequest.
The statuses table has a foreign key called worequest_id.
If someone is looking at a worequest, I want to allow them to create a new status record.
So, I created a button on the worequest show page. I thought that I would save the worequest.id in a global variable like this and link to create the new status record:
<% $current_request = #worequest.id %>
<%= link_to 'New Status', new_status_path, :class => 'btn btn-primary' %>
Then in the new status page, I have this code:
<% if $current_request == nil %>
<%= f.input :worequest_id, :label => 'Request ID' %>
<% else %>
<% f.text_field :worequest_id, :value => $current_request %>
<% $current_request = nil %>
<% end %>
But, the worequest.id field in the status record ends up being nil.
I also tried:
<% f.input :worequest_id, :value => $current_request %>
Any ideas?
You should just use sessions.
session[:worequest_id] = #worequest.id
Then when you get to the other page, just call the value back and put it in.
f.hidden :worequest_id, :value => session[:worequest_id]
Thanks Mizuho.
I used the session idea:
<%= f.hidden_field :worequest_id, :value => session[:worequest_id] %>
Before your comment, I didn't have the = after the <%. Once I put it in, it worked.
On the front page of my rap lyrics explanation site, there's a place where users can try explaining a challenging line:
alt text http://dl.dropbox.com/u/2792776/screenshots/2010-02-06_1620.png
Here's the partial I use to generate this:
<div class="stand_alone annotation" data-id="<%= annotation.id %>">
<%= song_link(annotation.song, :class => :title) %>
<span class="needs_exegesis"><%= annotation.referent.strip.gsub(/\n/, "\n <br />") %></span>
<% form_for Feedback.new(:annotation_id => annotation.id, :created_by_id => current_user.try(:id), :email_address => current_user.try(:email)), :url => feedback_index_path, :live_validations => true do |f| %>
<%= f.hidden_field :annotation_id %>
<%= f.hidden_field :created_by_id %>
<p style="margin-top: 1em">
<%= f.text_area :body, :rows => 4, :style => 'width:96%', :example_text => "Enter your explanation" %>
</p>
<p>
<% if current_user %>
<%= f.hidden_field :email_address %>
<% else %>
<%= f.text_field :email_address, :example_text => "Your email address" %>
<% end %>
<%= f.submit "Submit", :class => :button, :style => 'margin-left: .1em;' %>
</p>
<% end %>
</div>
However, putting more than one of these on a single page is problematic because Rails automatically gives each form an ID of new_feedback, and each field an ID like feedback_body (leading to name collisions)
Obviously I could add something like :id => '' to the form and all its fields, but this seems a tad repetitive. What's the best way to do this?
If you don't want to change your input names or your model structure, you can use the id option to make your form ID unique and the namespace option to make your input IDs unique:
<%= form_for Feedback.new(...),
id: "annotation_#{annotation.id}_feedback"
namespace: "annotation_#{annotation.id}" do |f| %>
That way our form ID is unique, i.e. annotation_2_feedback and this will also add a prefix, e.g. annotation_2_, to every input created through f.
Did you consider nested_attributes for rails models? Instead of having multiple new feedback forms where each is tied to an annotation, you could have multiple edit annotation forms where each annotation includes fields for a new feedback. The id's of the generated forms would include the annotations id such as edit_annotation_16.
The annotation model would have a relationship to its feedbacks and will also accept nested attributes for them.
class Annotation < ActiveRecord::Base
has_many :feedbacks
accepts_nested_attributes_for :feedbacks
end
class Feedback < ActiveRecord::Base
belongs_to :annotation
end
You could then add as many forms as you want, one for each annotation. For example, this is what I tried:
<% form_for #a do |form| %>
Lyrics: <br />
<%= form.text_field :lyrics %><br />
<% form.fields_for :feedbacks do |feedback| %>
Feedback: <br/>
<%= feedback.text_field :response %><br />
<% end %>
<%= form.submit "Submit" %>
<% end %>
<% form_for #b do |form| %>
Lyrics: <br />
<%= form.text_field :lyrics %><br />
<% form.fields_for :feedbacks do |feedback| %>
Feedback: <br/>
<%= feedback.text_field :response %><br />
<% end %>
<%= form.submit "Submit" %>
<% end %>
And the quick and dirty controller for the above edit view:
class AnnotationsController < ApplicationController
def edit
#a = Annotation.find(1)
#a.feedbacks.build
#b = Annotation.find(2)
#b.feedbacks.build
end
def update
#annotation = Annotation.find(params[:id])
#annotation.update_attributes(params[:annotation])
#annotation.save!
render :index
end
end
I had this same issue on a site I'm currently working on and went with the solution you mention at the bottom. It's not repetitive if you generate the ID programmatically and put the whole form in a partial. For example, on my site, I have multiple "entries" per page, each of which has two voting forms, one to vote up and one to vote down. The record ID for each entry is appended to the DOM ID of its vote forms to make it unique, like so (just shows the vote up button, the vote down button is similar):
<% form_for [entry, Vote.new], :html => { :id => 'new_up_vote_' + entry.id.to_s } do |f| -%>
<%= f.hidden_field :up_vote, :value => 1, :id => 'vote_up_vote_' + entry.id.to_s %>
<%= image_submit_tag('/images/icon_vote_up.png', :id => 'vote_up_vote_submit' + entry.id.to_s, :class => 'vote-button vote-up-button') %>
<% end -%>
I also had the same issue but wanted a more extensible solution than adding the ID to each field. Since we're already using the form_for ... |f| notation the trick is to change the name of the model and you get a new HTML ID prefix.
Using a variant of this method: http://www.dzone.com/snippets/create-classes-runtime (I removed the &block stuff)
I create a new model that is an exact copy of the model I want a second form for on the same page. Then use that new model to render the new form.
If the first form is using
#address = Address.new
then
create_class('AddressNew', Address)
#address_new = AddressNew.new
Your ID prefix will be 'address_new_' instead of 'address_' for the second form of the same model. When you read the form params you can create an Address model to put the values into.
For those stumbling here, looking for the solution for Rails 3.2 app, look at this question instead:
Rails: Using form_for multiple times (DOM ids)