Passing parameters on button click in Rails - ruby-on-rails

Right now, I have it so that when users pick an option from collection_select, a div is populated based on the event_id of their choice. Depending on the Event, there will be multiple EventOption shown, each with their own unique ids. (I have EventOption as belongs_to Event, each of which has_many of them.)
This is what I have populating via JS/Ajax when they select an Event:
<div class="center" >
<h2>Available Options for "<%= #event.name %>":</h2>
<% #event.event_options.each do |e| %>
<p><strong>Name:</strong> <%= e.name %> </p>
<p><strong>Description:</strong> <%= e.description %></p>
<p><strong>Price:</strong> <%= e.price %></p>
</div>
<div class = "center row">
<div class = "col-xs-6">
<%= link_to "Check Available Dates", root_path, :class => "button", :id => "available-dates-button" %>
</div>
<div class = "col-xs-6">
<%= link_to "Book This Event Now!", book_now_path(:event => #event.id), :id => "book-now-button", :class => "button" %>
</div>
<hr>
<% end %>
</div>
My issue is that I can pass the event_id when they click the Book This Event Now!, but that's not what I need. I need the specific :id of the :event_option to be passed over, and I don't know how to get it from the iterated .each I have it coming from.
How can I make sure that each iteration of a button that follows my book_now_path has a unique ID that I can use to complete their reservation?

Just add the event_option.id to your book_now_path helper.
book_now_path(:event => #event.id, :event_option_id => e.id)
Then in the controller action it will be in the params:
#event_option_id = params[:event_option_id]
You can add any additional parameters to the Rails routes helpers simply by adding their names and values as keys and values to the helper method's options.

Related

Issue with form_tag and select_tag in rails

I have a stats controller and view (with no model) that I use to show statistics from another model, company_model. I want to use a select form in the index view of stats and send the selected id from the company in order to hit the show action in stats controller, so i can render the specific stats from that company in particular.
This is how my form in view/stats/index.html.erb looks like:
<%= form_tag("stats", method: :get, enforce_utf8: false) do %>
<div class="form-row col-md-12">
<div class="col-md-4">
<%= select_tag :id, options_for_select(#companies.collect {|c| [ c.name, c.id ] }, params[:id]), include_blank: "Company", class: "form-control margin-bottom-sm" %>
</div>
<%= submit_tag("Show") %>
</div>
</div>
<% end %>
When I hit the buttom, I get stats?id=289&commit=show , and what I want to get instead is stats/289
I really appreciate some help.

Rails form_for sending params to controller action and not model

In the controller review_queue I have a custom action that posts a result to a target URL, I want to build a form for this action. I am not going to save any of the fields to the DB I am just going to pass them in the params to the post_review action.
def post_review
RestClient::Request.execute(:method => :post,
:url => Rails.application.secrets['target_url'],
:content_type => :json,
:payload => #result_params.merge!(params[:reasons]).to_json,
:headers => HEADERS)
end
In the view I have a form that will be filled out and on submit it should send up the reasons when the form is submited, I am setting the review_queue_id and the status in the form, since these are static, but the reasons should come from the textarea
<%= form_for(:review_queue, url: { action: 'post_review', :review_queue_id => #review_queue.id, :status => 'accepted'} ) do |f| %>
<div class='form-group'>
<label for='comment'>Please give a reason? (required)</label>
<%= f.text_area(:reasons, placeholder: 'Your commentns ...', rows: 9, class: 'form-control') %>
</div>
<div class='modal-footer'>
<%= f.submit 'Approve', class: 'btn btn-success btn-decission btn-modal-left-side' %>
<button type='button' class='btn btn-default' data-dismiss='modal'>Close</button>
</div>
<% end %>
error message:
NoMethodError - undefined method `reasons' for #<ReviewQueueApplication:0x007fa7ff7832d8>:
It seems as if rails is assuming the MVC architecture here, and assuming I want to pass the reasons to the review_queue model. there is no reasons column so it's dropping a no method error. Is there a way of specifying that the form is 'temporary' and only getting as far as the controller?
This seems like it should be a simple thing but there is some rails magic happening here.
NoMethodError - undefined method `reasons' for
ReviewQueueApplication:0x007fa7ff7832d8
form_for assumes that you are creating a form for a model object and expects the fields to be present in that specific model's table(in a normal situation).
You should be going with form_tag
<%= form_tag post_review_path, method: :get, :review_queue_id => #review_queue.id, :status => 'accepted'} ) do |f| %>
<div class='form-group'>
<label for='comment'>Please give a reason? (required)</label>
<%= text_area_tag(:reasons, placeholder: 'Your commentns ...', rows: 9, class: 'form-control') %>
</div>
<div class='modal-footer'>
<%= submit_tag 'Approve', class: 'btn btn-success btn-decission btn-modal-left-side' %>
<button type='button' class='btn btn-default' data-dismiss='modal'>Close</button>
</div>
<% end %>
And in the controller access it like params[:reasons]. Also if you noticed, I've added method: :get to the form_tag as you don't want to save the info to DB
The rails helper form_for is used for forms for rails resources. You want to use the form_tag helper. Search for form_for and form_tag here for more information on these 2 methods.

How to construct a clickable link with a scope using Ransack and Rails

I have the requirement to have some scopes as clickable links in my application. This will allow the user to change the data they are seeing as required. Using Ransack and it's ransackable_scopes functionality I am very close. I do need to retain any filtering Ransack has done when the user clicks the scope.
I've got the scopes working but now I just need to construct the clickable link.
Here's my model:
class Product < ActiveRecord::Base
scope :upward_trending, -> { where( "status > ?", 100).where(above_revenue_average: true).order('end_date DESC') }
scope :downward_trending, -> { where( "status < ?", 100).order('end_date DESC') }
def self.ransackable_scopes(auth_object = nil)
[:upward_trending, :downward_trending]
end
end
Now in my view I've added these two scopes as hidden fields, like so:
<%= search_form_for #q, :html => {:class => 'filter-form'} do |f| %>
<div>
<%= f.hidden_field :upward_trending %>
<%= f.hidden_field :downward_trending %>
<%= f.label :name_cont, "Search", class: 'label' %>
<%= f.search_field :name_cont, class: 'form-control input-box', :placeholder => 'Search' %>
</div>
<div>
<%= f.submit "Filter", class: 'btn btn-primary' %>
<%= link_to "Clear Search", request.path, class:"btn btn-default" %>
</div>
<% end %>
From here I just need to create the links and it should work.. What is the best way to do this?
Thanks for your help!
I was planning to do dirty way. (But haven't yet)
create search_form_for every scope (you will have 2 form for your case)
set hidden field with own criteria (as you do in your code but each in own form)
make submit button looks like link (with css I think it is not very difficult. You can see Bootstrap button appeared as link)
Not very clean or elegant.
I achieved this by creating hidden fields for each scope and then creating a button with onclick javascript:
<%= f.hidden_field :upward_trending %>
<%= button_tag(:type => 'submit', :class => 'btn btn-primary scope-button upward_trending', :id => "upward_trending", :onclick => "document.getElementById('q_downward_trending').value = 0; document.getElementById('q_upward_trending').value = 1;") do %>
<i class="fa fa-chevron-up fa-2x"></i><br>Upward<br>Trending
<% end %>

check_box_tag validate for form_tag

I have a problem with validating either at least one of the checkboxes was clicked before user can continue. My View looks likes this:
View:
<%= form_tag("/categories/", :method => "post") do%>
<% #categories.each do |category| %>
<div class="checkbox">
<li><%= check_box_tag "categories[]", category.id %> <%= category.name %></li>
</div>
<%end%>
<%= submit_tag "Weiter", class: "btn btn-success btn-lg" %>
class Category < ActiveRecord::Base
has_and_belongs_to_many :users
has_and_belongs_to_many :books
end
So what happens is that user registeres and gets the screen with all categories which are available in the category model. He then checks those and clicks proceed. On Post categories got associated with users. But how can I validate that the user chooses at least 1 category. If I do something like this it doesn't work:
validates_acceptance_of :categories,
:message => "Please take at least one category", :accept => true
You will want to validate the presence of categories.
validates :categories, presence: true
You can write your own validator
validate :at_least_one_category_selected
private
def at_least_one_category_selected
if self.categories.blank?
self.errors.add(:categories, "You must select at least one category.")
end
end
I have a solution, In this case I am calling a JS function before submitting the form. This will surely solve your problem.
<%= form_tag("/categories/", :method => "post", id: 'add-category-form') do%>
<% #categories.each do |category| %>
<li><%= check_box_tag "categories[]", category.id %> <%= category.name %></li>
<%end%>
<%= button_tag "Weiter", :class => 'btn btn-success btn-lg', id: 'add-category-btn', onclick: "validateCategoryPresent()" %>
<%end%>
Then in JS,
function validateCategoryPresent() {
event.preventDefault();
var checkboxes = Array.from(document.getElementsByName("categories[]"));
if(checkboxes.reduce((acc, curr) => acc || curr.checked, false)){
$('#add-category-form').submit();
} else {
//swal('Error','Please select atleast one channel!','warning');
alert('Some error!')
}
}
I called a JS function on the submit click of form_tag, (If you are using sibmit_tag replace it with button_tag)
I have prevented default behaviour of the submit button
Then I started to get the elements by its Id/Class or by Name, and checked what ever I want to do in the JS, and then based on my validation Either I am calling submit() on the form ID, or showing the error message.
Note: For showing error message I have used Sweet alert, you can stick with the alert();, but in case If you are looking for better UI, then uncomment my swal() code in JS and comment out alert();
You can read more about Sweet Alert PopUp

Multiple forms for the same model in a single page

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)

Resources