Rails Search Form - ruby-on-rails

I'm creating an application that tracks users and achievements (think, xbox live, etc.) These tables are linked via a join table. I would like to have a search form on my index that lets users type in a users name and a new page is loaded with a list of all achievements that user has earned. I'm not entirely sure how to set up this search form, on the index, to actually search the user table and return the results on a new page. Any help would be greatly appreciated. If you require more information then I'll be happy to provide it.

Here's a bit of skeleton code to get you started based off what I think you need from what you have said. I hope this is useful.
For the search bit you could do something like this in your index view:
<%= form_for User.new, :url => "search" do |f| %>
<%= f.label :name %>
<%- f.text_field :name %>
<%- end %>
In your controller:
def search
q = params[:user][:name]
#users = User.find(:all, :conditions => ["name LIKE %?%",q])
end
and in your search view:
<%-#users.each do |user| %>
Name: <%=user.name %>
<%- user.achievements.each do |achievement| %>
<%= achievement.name %>
<%- end %>
<%- end %>
You would, of course, need to ensure the users and achievement models are correctly linked:
class User << ActiveRecord::Base
has_many :achievements
end

There are plenty of tutorials and things about this e.g.:
http://blog.devinterface.com/2010/05/how-to-model-a-custom-search-form-in-rails/
Look the thing is every basic explanation in Rails3 starting with the Initial Tutorial provided by them explains you how to setup a new Controller/Model. The example was only one of thousands explaining the same problem.
It is a very broad range of different things you can do to achieve this. Basically you have to put some code in the controller:
which handles the search (including the activerecord stuff or whichever technique you use to access your model)
which sets some variables necessary for the search form
Setup two routes etc... Its to broad and completely covered even by the basic official rails3 tutorial.

Here is an application based on searchlogic is very useful and you can search by whatever you want
https://github.com/railscasts/176-searchlogic

You may want to check out the Ransack gem. https://github.com/activerecord-hackery/ransack

Related

Rails search form, two models

I am trying to implement a search field in Rails 4 to find data behind two models. I have two controllers: buildings and rooms, and two models: building and room. A building, naturally, has many rooms and a room belongs to a building, which I have stated in the respective models.
Basically, a user could type either a building or a room name into the search form and it would return a response with details about the building or room. Of course, a building needs to have an address, and a room needs to know in which building it is with the address as well. So I'd need to display different details according to the searched for instance. Both have the same String attribute name, so this could make things easier.
I have no luck in finding a relevant example on how to implement such a search form. This is the working basic search I have at the moment in views\buildings\index.html.erb, which can only search buildings:
<%= form_tag({controller: "buildings", action: "show"}, method: "get", class: "nifty_form") do %>
<%= label_tag(:name, "Search for a building (later also rooms):") %>
<%= text_field_tag(:name) %>
<%= submit_tag("Search") %>
<% end %>
This is the show method in controllers\buildings_controller.rb:
def show
#building = Building.where('lower(name) = ?', params[:name].downcase).first
end
And this is the route it refers to:
get 'buildings/:id' => 'buildings#show'
Any and all help is appreciated!
I would recommend you to add the search code in the index method of buildings controller, there are many things you can do but here is what i will recommend:
def index
#
if params.has_key?(:name)
#buildings = Building.joins(:rooms).
where([
'lower(buildings.name) like ? or lower(rooms.name) like ?',
"%#{params[:name].downcase}%",
"%#{params[:name].downcase}%"
])
else
# your normal code goes here.
end
end
Any other information you need such address ( is that a different model ) can he included in there.
Hope this helps,
PD: if necessary you can render a different view when a search is present inside your if block
render action: 'my_custom_view', status: :ok
Due to time restrictions, I decided to merge these models into one common model, Space. It holds all the information that a building and a room needs. Thanks anyways!

I need a very simple search gem for just searching the partyname on a sqlight3 database?

My party registry Rails 3 app needs a search function for visitors to search a partyname and then be able to click on the party and go to the show page of that party. Must be very simple ajax list that pops up without reloading etc.
The app is almost done and runs off a sqlight3 database.
Any suggestions - tried all the RailsCasts ones and nothing fits right 100%.
Thanks in advance.
I think you want two different things.
1) To create a simple search you can do something like this.
2) To autocomplete while typing (partyname for example) you can use the autocomplete gem.
You must decide which approach you want to follow.....
I hope if helps in some way...
EDIT - to show how to implement the simple search.
let's say you have a model called Party
your form (index page for example):
...
<%= form_tag parties_path, method: :get do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", name: nil %>
<% end %>
...
#display results
<% #parties.each do |party| %>
...
<% end %>
model Party:
...
def self.search(search)
# if search is not empty
if search
find(:all, :conditions => ["partyname LIKE ?", "%#{search}%"])
# if search is empty return all
else
find(:all)
end
end
...
controle parties_controller:
#parties = Party.search(params[:search])
Try smart_search gem
gem install smart_search
Does everything that needs to be done to make your model searchable!

ransack search form in header partial: No Ransack::Search object was provided to search_form_for

First of all, I'm new to RoR, so the answer may be obvious, in which case I apologize. I've looked around and haven't found anything that helps.
I'm trying to have a search form at the header of every web page on my app that will search through the names of all my "buckets". Here is the relevant code:
In app/views/layouts/_header.html.erb (within a nav bar):
<% search_form_for #q do |f| %>
<%= f.label :name_cont %>
<%= f.text_field :name_cont %>
<%= f.submit %>
<% end %>
In app/controllers/buckets_controller.rb:
def index
unless params[:q].blank?
#q = Bucket.search(params[:q])
#buckets = #q.result.paginate(:page => params[:page])
else
#buckets = Bucket.find(:all, :limit => 5).paginate(:page => params[:page])
end
end
I understand the last part isn't that great: what I'm trying to do is if I'm just accessing the bucket index page (not by searching), i display the 5 most recently created buckets. When I search for something in the header form, I access the index page but only show the buckets that hit the search. (would a better way to handle it to have a search page separate from my index page?)
I found this issue which is pretty much identical, but I still don't see how I handle #q if every page is going to have the form on it--surely I don't have to alter every controller's every action?
Sorry in advance for any frustration my noobishness my cause you!
As others have said, you need to utilize the ApplicationController's before_filter. Though ernie himself seems not to recommend this, the implementation is simple.
First, use the advanced Ransack options to set your path for your search thusly
#config/routes.rb
resources :buckets do
collection do
match 'search' => 'buckets#search', via: [:get, :post], as: :search
end
end
Second, update your BucketsController to include the following custom action:
#controllers/buckets_controller.rb
def search
index
render :index
end
Nothing yet out of the ordinary. If you currently try to search you will get the error from your original question. Your definition of the variable q is correctly implemented, but you will have to move it to the ApplicationController like so:
#controllers/application_controller.rb
before_filter :set_global_search_variable
def set_global_search_variable
#q = Bucket.search(params[:q])
end
Finally, update your search form to pass in the correct search options
#layouts/_header.html.erb
<% search_form_for #q, url: search_buckets_path, html: { method: :post } do |f| %>
<%= f.label :name_cont %>
<%= f.text_field :name_cont %>
<%= f.submit %>
<% end %>
No, you do not need to edit all your controllers.
You can use ApplicationController for all your "common" controller needs. Read up on it in the guides http://guides.rubyonrails.org/action_controller_overview.html and the API docs http://api.rubyonrails.org/classes/ActionController/Base.html
The key here is, when you generated your new rails app, you'll notice it created the file .../app/controllers/action_controller.rb and that class derives from ActionController::Base. Then, if you again use the rails generator to create a controller for your app, you'll notice your new controller class derives from ApplicationController (not ::Base). That means that the application_controller.rb is the parent controller class for your app. That means everything in it is available to all your app controllers. It's easy to abuse, so be judicious.
Looks like this is not possible. This is a comment from Ernie the gem author.
You'd have to handle the Ransack-required stuff in a before_filter or
(ick) in the view partial itself. If you're putting a search field on
every single part of the site, I'd recommend you strongly consider
whether ransack is the right tool for the job, as well. You might want
some sort of inverted index search setup like sphinx, solr, etc.
https://github.com/ernie/ransack/issues/3

Using one search form to search multiple models

I am working a simple rails app and i would like to know how possible it is to use one search form to search inside multiple models. like i have a story model and a book model. this search form should be able to search the both models with a single parameter.
<%= for_tag :url => search_path %>
<%= text_field_tag :q %>
<% end %>
How can i make this search from work for multipple models
Whatever search you need to do, is done inside an action in a controller. You could basically create a controller, say search_controller and have an action say, item
def item
if params[:q]
#found_stories = Story.find_all_by_...(params[:q])
#found_books= Book.find_all_by_...(params[:q])
end
end
Then you could use the objects #found_stories and #found_books in your view to show the search results.
This is just an example of how you could do to fulfill your requirement.
Thanks.

Rails Form Builders - How to display a read only field or protect a field

I have created a form that needs to show data from 2 tables (parent and child). When the form is submitted only the child fields are updated (the parent fields are meant to be display only). While the parent model fields are displayed these need to be protected from updates (preferably via the formbuilder, rather than via css).
FWIW this is a pretty common master/detail use case. However I have not been able to find any examples of this - most of the examples I've seen seem to be trivial/single model display/update where all displayed fields are updateable).
Any ideas/samples/suggestion/tutorials/examples of real world, multi model Rails forms would be helpful.
TIA
Just out of interest, why bother going through the motions of creating a multi-model form when you only want to update the child record? My advice would be keep your form simple, I.e. make it a child form and just display the data from the parent record. If needs be, you could even style that display to look like part of the form, although I think that may throw the user off.
If you really need to do what you are doing, I would still use CSS to disable/readonly the input fields and in your controller update action, only pass the attributes you want to update into the update_attributes method call.
Finally, maybe look into the attr_protected method to prevent the fields you may want protecting from accidental mass-assignment.
I agree with tsdbrown, I don't think a complex form is required. If you'd like to learn more about complex forms or you really have your heart set on using a complex form I'd recommend watching the Railscasts episodes (73 - 75).
As tsdbrown said before, you are adding a complexity layer to your forms that's not need. If all you want is to update a detail model, while showing some info of it's parent, you could just do so with something like:
Order number: <%= #line_item.order.number %>
Order date: <%= #line_item.order.order_date %>
<% form_for #line_item do |f| %>
<%= f.label :quantity %>
<%= f.text_edit :quantity %>
<% end %>
When you'd like to edit both, then you can research on the field_for and nested forms methods (the Railscasts suggestion mentioned before it's great).
Thx for the responses which helped resolve my problem/question. Just want to close this out in case it helps others in the future.
Turns out I had been getting an error trying to reference my parent data element (patients.lname) as it was being passed in an array of results, rather than as a single result. In my view controller I had:
#visit = Visit.all(:select => "visits.id, visits.visittype, visits.visitdate, events.patient_id, patients.lname",
:conditions => ["visits.id = ?",params[:id] ],
:joins => "INNER JOIN events on events.id = visits.event_id INNER JOIN patients on patients.id = events.patient_id" )
In my view I had (this was giving me an invalid reference as I was doing a find all above):
<h1>Editing visit for patient :
<%= #visit.lname %> # should be <%= #visit[0].lname %>
</h1>
Below is the improved (and simpler) version where I find the specific record I need (basically replacing find all with find first):
#visit = Visit.find(:first, :select => "visits.id, visits.visittype, visits.visitdate, events.patient_id, patients.lname",
:conditions => ["visits.id = ?",params[:id] ],
:joins => "INNER JOIN events on events.id = visits.event_id INNER JOIN patients on patients.id = events.patient_id" )
And in the view:
<% form_for(#visit, :builder => LabelFormBuilder) do |f| %>
<%= f.error_messages %>
Name: <%= #visit.lname %>
<%= f.text_field :visittype %>
<%= f.date_select :visitdate %>
<p>
<%= f.submit 'Update' %>
</p>
<% end %>
Sometimes it's hard to see the wood for the trees! Hope this helps someone else.

Resources