Ruby on Rails : Advance search, undefined method [ ] for nil:Nil class - ruby-on-rails

I am very new to rails and try to make an advance search form which takes two values 'blood_group' and 'area' and based upon that search the records from the database are fetched and will display on the same page (find.html.erb)
I have tried something in find.html.erb but there is an error occurred 'undefined method [] for nil:Nil class' where my search form exists. please help to get out of this error.
Here is my search form in find.html.erb
<%= form_tag find_path , method: :get do %>
<p> <%= label_tag :blood_group %><br />
<%= select_tag (:blood_group), options_for_select(%w[ A+ B+ O+ AB+ A- B- O- AB-]), params[:blood_group] %> </p>
<p> <%= label_tag :area %><br />
<%= select_tag (:area), options_for_select(%w[Indore Vijay_Nagar Bhawar_Kuwa Rajendra_Nagar Geeta_Bhawan Aerodram Tejaji_Nagar Raj_Mohalla Rajwada Chandan_Nagar Gandhi_Nagar Arvindo MY Bombay_Hospital]) , params[:area] %> </p>
<%= submit_tag "Search" , class: "btn btn-primary" , name: nil %>
<% end %>
The error is at the lines where I used select tag.
below is my find action in Donor controller
def find
#donors = Donor.search(params[:blood_group], params[:area]).all
end
And Donor.rb is as follows
class Donor < ActiveRecord::Base
def self.search(blood_group, area)
return all unless blood_group.present? || area.present?
where(['blood_group LIKE ? AND area LIKE ?', "%#{blood_group}%", "%#{area}%"])
end
end

Your search form must be like this:
<%= form_tag find_path , method: :get, remote: true do %>
<p> <%= label_tag :blood_group %><br />
<%= select_tag (:blood_group), options_for_select(%w[ A+ B+ O+ AB+ A- B- O- AB-]) %> </p>
<p> <%= label_tag :area %><br />
<%= select_tag (:area), options_for_select(%w[Indore Vijay_Nagar Bhawar_Kuwa Rajendra_Nagar Geeta_Bhawan Aerodram Tejaji_Nagar Raj_Mohalla Rajwada Chandan_Nagar Gandhi_Nagar Arvindo MY Bombay_Hospital]) %> </p>
<%= submit_tag "Search" , class: "btn btn-primary" , name: nil %>
<% end %>
Modify your controller as:
def find
#donors = Donor.search(params[:blood_group], params[:area]).all
respond_to do |format|
format.js
end
end
Then add find.js.erb to show the searched content.

Related

I'd like to add radio buttons to the Rails search function to allow narrowing the search

What I want to come true
I want to implement a search function using radio buttons. I want to be able to narrow down the search using radio buttons and search words.
I've gotten as far as how to implement search, but I can't figure out how to narrow it down with radio buttons. I would like to know how to do this.
code
View
<div class="form">
<%= form_with url: search_path, method: 'get' do |form| %>
<div class="search">
<%= form.text_field :search %>
<%= form.submit "Search" %>
</div>
#I don't know how to send the value of a radio button.
<div class="radio">
<%= form.label :search_check_box,"all", {value: :all} %>
<%= form.radio_button :search_check_box, :all %>
<%= form.label :search_check_box,"public", {value: : public} %>
<%= form.radio_button :search_check_box, :public %>
<%= form.label :search_check_box,"not_ public", {value: :not_ public} %>
<%= form.radio_button :search_check_box, :not_publick %>
</div>
<% end %>
</div>
controller
def search
#movies = Movie.search(params[:search])
end
model
class Movie < ApplicationRecord
def self.search(search)
if search
Movie.where('name LIKE ?', "%#{search}%")
else
Movie.all
end
end
end
You're falling to the classic trap of using a single class (Movie) to do way too much. Create a separate model to use to wrap the logic for searching:
class MovieQuery
include ActiveModel::Model
include ActiveModel::Attributes
VISIBILITY_OPTIONS = ["all", "public", "private"]
attribute :name
attritute :visiblity
def to_scope(base: Movie.all)
base.tap do |b|
b = base.where('name LIKE ?', "%#{ name }%") if name.present?
b = base.where(visiblity: visiblity) if ["public", "private"].include?(visiblity)
end
end
end
This model is not saved to the database - it simply serves to bind the user input to an object and apply the search filters. Its also the local place to add stuff like validations.
Then bind the form to your model:
<%= form_with model: #movie_query || MovieQuery.new, url: search_path, method: 'get' do |form| %>
<div class="search">
<%= form.label :name, 'Search by name' %>
<%= form.text_field :name %>
</div>
<div class="radio">
<%= form.label :visiblity %>
<%= form.collection_radio_buttons :visiblity,
MovieQuery::VISIBILITY_OPTIONS,
:itself,
:humanize
%>
</div>
<div class="actions">
<%= form.submit 'Search' %>
</div>
<% end %>
collection_radio_buttons is really meant to be used with objects (models) and the third and forth arguments are the text and label methods called on each object in the collection. By using itself and humanize you can use it with a simple array.
Then setup your controller to bind the inputs back to the model:
class MoviesController
def search
#movie_query = MovieQuery.new(search_parameters)
#movies = #movie_query.to_scope
end
private
def search_parameters
params.fetch(:movie_query) # its an optional parameter
.permit(:name, :visibility)
end
end

using an instance of appointment in the appointment model

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" %>

Ruby On Rails - validate nested params in controller (must not be nil)

These are my params:
{"utf8"=>"✓", "authenticity_token"=>"0RYiIDDgmOk0gCDRkAgHvv+UIgp/BuU33CLThJXqOTE=",
"order"=>
{"operation_in_orders_attributes"=>
{"0"=>{"service_operation_id"=>"5"},
"1"=>{"service_operation_id"=>""},
"2"=>{"service_operation_id"=>"4"},
"3"=>{"service_operation_id"=>""},
"4"=>{"service_operation_id"=>""}},
"kontakt"=>"comment", "Car_id"=>"50"},
"commit"=>"Dodaj",
"car_id"=>"dw815gn"}
Order has many operation_in_orders
Order has many service_operations through OperationInOrder
OperationInOrder belongs to Order
OperationInOrder belongs to ServiceOperation
ServiceOperation has many operation_in_orders
ServiceOperation has many orders through OperationInOrder
My form:
<%= form_for #order, url: new_car_order_path(#car, #order), html: {class: "add_order"} do |r| %>
<%= r.label "Service", class: :add_order_label %>
<% 5.times do %>
<%= r.fields_for :operation_in_orders do |v| %>
<%= v.collection_select(:service_operation_id, ServiceOperation.all, :id, :nazwa,include_blank: true) %>
<!-- <%= v.text_field :order_id, value: #order.id, :style => "display:none" %> -->
<% end %>
<% end %>
<%= r.label "Kontakt", class: :add_order_label %>
<%= r.text_field :kontakt %>
<%= r.text_field :Car_id, value: #car.id, :style => "display:none" %>
<%= r.label " " %>
<%= r.submit "Add", class: "sub" %>
<%= link_to "Send",ordered_path(car_id: #car.id) , class: 'sub'%>
<% end %>
I have a form where I can choose five ServiceOperations at most to an order and save.
When I save, 5 new OperationInService objects/rows are made.
Is there a possibility to not create those join tables if corresponding field on form is blank?
For example:
I fill only 2 from 5 fields. I save only these two, not 5. Now I save nil values...
I have tried to validate in OperationInService model, but there was an error (rails do not recognize format in controller).
Any ideas?
Update the accepts_nested_form_for method call in Order model as below:
class Order < ActiveRecord::Base
has_many :operation_in_orders
accepts_nested_attributes_for :operation_in_orders, reject_if: proc { |attributes| attributes['service_operation_id'].blank? }
## ..
end
This way record for operation_in_orders would not be created if service_operation_id is blank.

Rails check_box_tag within form_for

Is it possible to pass the value of checked check_box_tags within a form_for in Rails inside a hash?
Here is a very generic, basic version of the form:
<%= form_for(:object, :url => { :action => 'create', :id => params[:id]}) do |f| %>
<p>Field_a: <%= f.text_field(:field_a) %></p>
<p>Field_b: <%= f.text_field(:field_b) %></p>
<p>Field_c: <%= f.text_field(:field_c) %></p>
<p>Check boxes:</p>
<% check_box_choices_object_array.each do |s| %>
<%= check_box_tag(s.name, 1, false) %>
<%= .name %><br />
<% end %>
<%= submit_tag("Create") %>
<% end %>
Outputs roughly:
Field_a ___________________
Field_b ___________________
Field_c ___________________
Check boxes:
[] box_a
[] box_b
[] box_c
[] box_d
[] box_e
[] box_f
[] box_g
My problem is that since the available check boxes aren't actual fields in the object's table in the database (i.e. I'm not using check_box(:field) in the form), each checked check box gets passed as an individual parameter (i.e. "box_a" => "1", "box_b" => "1", "box_e" => "1"). I would like them to be passed as such:
:checked_boxes => {"box_a" => "1", "box_b" => "1", "box_e" => "1"}
This way, I can access them easily with params[:checked_boxes].
How do I do this, or, better yet, is there a better solution (I'm new to rails)?
I think you'd get the results you want if you wrap the checkboxes iterator in a fields_for :checked_boxes tag - or at least get you close to the results you want.
<%= form_for(:object, :url => { :action => 'create', :id => params[:id]}) do |f| %>
<p>Field_a: <%= f.text_field(:field_a) %></p>
<p>Field_b: <%= f.text_field(:field_b) %></p>
<p>Field_c: <%= f.text_field(:field_c) %></p>
<p>Check boxes:</p>
<%= f.fields_for :checked_boxes do |cb| %>
<% check_box_choices_object_array.each do |s| %>
<%= cb.check_box(s.name, 1, false) %>
<%= .name %><br />
<% end %>
<% end %>
<%= submit_tag("Create") %>
<% end %>
you can deal with no database attributes and models using attr_accessor
class Thing < ActiveRecord::Base
attr_accessible :name
attr_accessor :box_a, :box_b, :box_c
end
This way you can call these attributes in your form.

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