How do I set default search conditions with Searchlogic? - ruby-on-rails

I've got a search form on this page:
http://staging-checkpointtracker.aptanacloud.com/events
If you select a State from the dropdown you get zero results because you didn't select one or more Event Division (checkboxes).
What I want is to default the checkboxes to "checked" when the page first loads...to display Events in all Divisions...but I want changes made by the user to be reflected when they filter.
Here's the index method in my Events controller:
def index
#search = Event.search(params[:search])
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #events }
end
end
Here's my search form:
<% form_for #search do |f| %>
<div>
<%= f.label :state_is, "State" %> <%= f.select :state_is, ['AK','AL','AR','AZ','CA','CO','CT','DC','DE','FL','GA','HI','IA','ID','IL','IN','KS','KY','LA','MA','MD','ME','MI','MN','MO','MS','MT','NC','ND','NE','NH','NJ','NM','NV','NY','OH','OK','OR','PA','RI','SC','SD','TN','TX','UT','VA','VT','WA','WI','WV','WY'], :include_blank => true %>
</div>
<div>
<%= f.check_box :division_like_any, {:name => "search[:division_like_any][]"}, "Sprint", :checked => true %> Sprint (2+ hours)<br/>
<%= f.check_box :division_like_any, {:name => "search[:division_like_any][]"}, "Sport" %> Sport (12+ hours)<br/>
<%= f.check_box :division_like_any, {:name => "search[:division_like_any][]"}, "Adventure" %> Adventure (18+ hours)<br/>
<%= f.check_box :division_like_any, {:name => "search[:division_like_any][]"}, "Expedition" %> Expedition (48+ hours)<br/>
</div>
<%= f.submit "Find Events" %>
<%= link_to 'Clear', '/events' %>
<% end %>

There are a few ways to do this, I think the easiest/quickest way is:
#search = Event.search(params[:search] || Event::DEFAULT_SEARCH_PARAMETERS)
In event.rb
class Event < A:RB
DEFAULT_SEARCH_PARAMETERS = {:state_is => 'NY', :foo => 'bar'} # set your defaults here
end
Having said that, I'm not sure how that's going to work with the checkboxes. You could also consider one of the following options:
Have a SearchSetting model which contains all the searchable parameters (you can also persist this for users if they can save searches, or just leave it disconnected). This will make your form much simpler.
Add an All Divisions checkbox which is checked by default. A little bit of javascript to manage the state of the checkboxes and a custom search method.

Related

How to do the calculation without any models in Rails?

I need to get an integer(#integer) from the form in my root_path, do multiplication (#integer*45) and display the result on the same page. How can I do it without any models in my application?
Please, share your best practice. Thank you!
I was trying to do next:
CalculatorsController
def calculation
#integer = params[:integer]
#result = #integer*45
end
def result
end
root.rb
root :to => 'calculators#result'
resources :calculators, :collection=>{:result => :get, :calculation => :post}
calculators/result.html.erb
<% form_tag root_path, :html => {:method => :post} do %>
<%= label_tag 'integer' %>
<%= text_field_tag :integer %>
<div><%= submit_tag 'OK' %></div>
<% end %>
I'll do it with ajax, so there is no need for page refresh:
First, update the routes, for your example you only need two routes, one get (or root) and one post.
routes.rb:
Rails.application.routes.draw do
root 'calculators#result'
post 'calculators/calculation'
end
Next, update your view:
Change the url in your form_tag where the data will be sent (to calculation action instead of result).
Add remote: true option to enable ajax.
Add a tag where you will display your result.
result.html.erb:
<% form_tag calculators_calculation_url, remote: true do %>
<%= label_tag 'integer' %>
<%= text_field_tag :integer %>
<div><%= submit_tag 'OK' %></div>
<% end %>
<div id="total"></div>
And create a view for calculation action, but since you are using ajax, you will create it as js.erb and include the required javascript (or jQuery) to update your view (i'm using jQuery in the example).
calculation.js.erb:
$('#total').html('<%= #result %>')
Now when you click submit, your form will be sent to calculation action and will update the div with #result.
Just add the field to your form...
<% form_tag root_path, :html => {:method => :post} do %>
<%= label_tag 'integer' %>
<%= text_field_tag(:integer, #integer) %>
<% if #result.present? %>
<br>
Result is: <%= #result %>
<br/>
<% end %>
<div><%= submit_tag 'OK' %></div>
<% end %>
And then render result in your calculate...
def calculation
#integer = params[:integer].to_i
#result = #integer*45
render :result
end
Your result view (result.html.erb) is getting its data from the result method, not calculation. Update your controller as follows:
def calculation
#integer = params[:integer]
end
def result
#result = #integer*45
end
You then need a tag to display your result in the view, something like:
<p> <%= #result %> </p>

Ruby on Rails: Why isn't my search working?

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.

How do I pass params through an AJAX form to create.js while retaining the params?

I have some comments that have a vote score, and I filter them by recent and popular using a toggle. When I click popular, it passes sort: popular as params, and resorts the comment list based on that. Then when a user posts another comment using AJAX, i'm trying to keep the comments sorted by popular (instead of reverting to the default recent) by passing the sort params through the comment form to the controller, and on to create.js, where it sorts the comments based on the params pass in. This works once, but as soon as I post 2 comments, it reverts back to sorting by recent, because i'm not able to continue passing the sort parms.
My sort toggle:
<% if params[:sort] == 'popular' %>
sorted by <%= link_to("Recent", video_path(video), remote: true, class: 'gray-link') %> |
<%= link_to("POPULAR", video_path(video, sort: 'popular'), remote: true, class: 'gray-link') %>
<% else %>
sorted by <%= link_to("RECENT", video_path(video), remote: true, class: 'gray-link') %> |
<%= link_to("Popular", video_path(video, sort: 'popular'), remote: true, class: 'gray-link') %>
<% end %>
The comments form, where I pass my params as a hidden field called :sort - note, they are nested comments, hence the form_for syntax, but it should be irrelevant here.
<%= form_for [#video, #comment, , :html => {:class => 'form_height'}], :remote => true, method: :post, url: video_comments_path(#video.id) do |f| %>
<div id="comment-form-errors">
<%= render :partial => "/videos/comment_form_errors" %>
</div>
<%= f.hidden_field :parent_id, :value => parent_id %>
<%= f.hidden_field :sort, value: params[:sort] %>
<%= f.text_area :post, placeholder: 'Comment', id: 'comment-box' %>
<% if parent_id != nil %>
<%= f.submit "Reply" %>
<% else %>
<%= f.submit %>
<% end %>
<% end %>
Then in the controller I create a variable #sort to collect the sort params from the comment form:
def create
#comment = #video.comments.build(comment_params)
#comment.user = current_user
#sort = params[:comment][:sort]
respond_to do |format|
if #comment.save
format.html { redirect_to video_path(#video.id), notice: "You said something. Let's hope it didn't suck." }
format.js { }
else
format.html { render 'videos/show', alert: "There was an error." }
format.js {}
end
end
end
Then I order the comments based on whether the popular sort params was passed:
<% if #comment.errors.present? %>
$('#comment-form-errors').html("<%= escape_javascript(render(:partial => '/videos/comment_form_errors')) %>");
<% else %>
<% if #sort == 'popular' %>
$('#comment-list').html("<%= j nested_comments (#video.comments).arrange(:order => 'cached_weighted_score DESC') %>");
<% else %>
$('#comment-list').html("<%= j nested_comments (#video.comments).arrange(:order => 'created_at DESC') %>");
<% end %>
$('#review-form-errors').html('');
$('textarea#comment-box').val('');
$('#comment-counter').text("<%= pluralize(#video.comments.count, 'comment') %>");
$('.error-explanation').text('');
<% end %>
HERE'S THE PROBLEM: The first time around my server logs show params being sent as: Parameters: {"utf8"=>"✓", "comment"=>{"parent_id"=>"321", "sort"=>"popular", "post"=>"c"}, "commit"=>"Reply", "video_id"=>"283"} - which is great, I post a comment and the comments, if sorted by popular, stay sorted by popular.
But if I post a second consecutive comment, it's not passing the sort params: Parameters: {"utf8"=>"✓", "comment"=>{"parent_id"=>"322", "sort"=>"", "post"=>"d"}, "commit"=>"Reply", "video_id"=>"283"} - my comments reverts to sorting by the default, recent.
I don't know where to go from here. I feel like i'm missing something small, but no amount of searching around has found the solution. Can anyone point me in the right direction, I would really appreciate any ideas on how to get this working, or if need be, how to rework my solution if there's a better way to do this.
THANKS!
EDIT: With MravAtomski's help I was able to get this working. I changed my comment form to:
<% if params[:comment] %>
<%= f.hidden_field :sort, value: params[:comment][:sort] %>
<% else %>
<%= f.hidden_field :sort, value: params[:sort] %>
<% end %>
And in my comment controller create action I added:
if params[:sort]
#sort = params[:sort]
elsif params[:comment][:sort]
#sort = params[:comment][:sort]
end
My guess is that after the first form submit the 'sort' hidden field looses it's value so it does not get sent it in next submit.
<%= f.hidden_field :sort, value: params[:sort] %>
maybe it should be
<%= f.hidden_field :sort, value: params[:comment][:sort] %>
because a comment object is being used in the form_for.
Also this is probably not the case but check if it is doing ajax requests and not html requests. If it's doing html requsests then it probably loses the 'sort' hidden value due to page refresh.
EDIT
so when page loads it uses params[:sort] then after create submit it uses params[:comment][:sort], maybe something like this can be used as quick solution:
<%= f.hidden_field :sort, value: params[:sort] || params[:comment][:sort] %>
Other solution would be to add a data attribute to one of tags that is not changed via create ajax request. i.e. form tag. add a data-sort attribute to form tag used to create comments:
<%= form_for [#video, #comment, , :html => {:class => 'form_height ..., :data-sort => params[:sort] do |f| %>
When comment is created don't change the data-attribute, it should only be set when user changes sorting and send it as ajax request parameter every time sort value is needed.

Why does this select field appear multiple times in my Rails form?

I've got a Rails application that is using nested forms. Details follow and I tried this solution (Rails 3 Nested Models unknown attribute Error), but for some reason, the field is repeating multiple times instead of listing and saving the options correctly. Thanks in advance for your help!
Model information for Newsavedmaps
has_many :waypoints, :dependent => :destroy
accepts_nested_attributes_for :waypoints
Newsavedmap_controller
def new
#newsavedmap = Newsavedmap.new
waypoint = #newsavedmap.waypoints.build
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #newsavedmap }
end
end
def edit
#newsavedmap = Newsavedmap.find(params[:id])
if #newsavedmap.itinerary.user_id == current_user.id
respond_to do |format|
format.html # edit.html.erb
format.xml { render :xml => #activity }
end
else
redirect_to '/'
end
end
Maptry View
<% form_for #newsavedmap, :html=>{:id=>'createaMap'} do |f| %>
<%= f.error_messages %>
<% f.fields_for :waypoint do |w| %>
<%= w.select :waypointaddress, options_for_select(Waypoint.find(:all, :conditions => {:newsavedmap_id => params[:newsavedmap_id]}).collect {|wp| [wp.waypointaddress, wp.waypointaddress] }), {:include_blank => true}, {:multiple => true, :class => "mobile-waypoints-remove", :id =>"waypoints"} %>
<% end %>
<% end %>
When I use the above code, my form works correctly, but submitting it gives me this error:
UnknownAttributeError (unknown attribute: waypoint)
When I change ":waypoint do |w|" to ":waypoints do |w|" in the view, the select field disappears when the user is creating a new record, and in the edit view, the select field appears several times (however many waypoints the user saved in the record.)
How can I get this form field to work properly?
EDIT 1
Here is my latest attempt. For new records, the select field does not appear. However, in the edit view, the select field appears multiple times. This is a Rails 2 application, FYI. Taking a cue from the comments, I used a collection_select approach (not collection_for_select because I couldn't find documentation for that.) Again, I appreciate your help!
<% f.fields_for :waypoints do |w| %>
<%= w.collection_select( :waypointaddress, #newsavedmap.waypoints, :waypointaddress, :waypointaddress, {:include_blank => true}, {:id =>"waypoints"} ) %>
<% end %>
Your form has the following problems.
Use f.fields_for :waypoints since the argument needs to match the name of the association.
Use collection_select rather than select, since you have an ActiveRecord model behind that field.
So, taking that into account, you could try this for your form:
<% form_for #newsavedmap, :html => { :id => 'createaMap' } do |f| %>
<%= f.error_messages %>
<% f.fields_for :waypoints do |w| %>
<%= w.collection_for_select :waypoint, :waypointaddress, #newsavedmap.waypoints, :waypointaddress, :waypointaddress, { :include_blank => true }, { :multiple => true, :class => "mobile-waypoints-remove", :id =>"waypoints" } %>
<% end %>
<% end %>
The API for collection_select is a bit tricky to get right. I usually need a few attempts as well. This previous SO question may help clear things up: Can someone explain collection_select to me in clear, simple terms?

Trouble accessing a hidden_field_tag value passed to controller in rails form

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]

Resources