I'm new to RoR and I've managed to make a basic search form but keep getting errors when trying to expand the search tags (name).. I have a model with various data (location, website, email, telephone) and was wondering how I can add these to my current search code.
/models/ciir.rb
def self.search(search)
if search
find(:all, :conditions => ['name LIKE ?', "%#{search}%"])
else
find(:all)
end
end
static_pages_controller.rb
def home
#ciirs = Ciir.search(params[:search])
end
/home.html.erb
<%= form_tag ciirs_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag " Search Database Records ", :name => nil %>
</p>
<% end %>
When clicking the submit button (no search terms) the url is:
ciirs?utf8=✓&search=
but when modifying the name condition to something like 'website' the url changes to
ciirs?utf8=✓&search=&commit=+Search+Database+Records+ –
Since you mentioned you are new to RoR, I must share the way I learned RoR was reading, using and analyzing one issue at a time. I would suggest you to take a look at following points one at a time and try & learn how RoR treats them and how these fit your question:
How form_tag works?
How text_field_tag works?
Once you have understood form_tag, difference between text_field_tag and f.text_field?
How params objects are created, and it uses names of form controls?
How and when to use GET and/or POST form methods? Inadvertently, what are different types of method and when to use them?
How URL are used in the form_tag and what components are they made of?
Sprinkle a bit of knowledge of Ruby language by learning between Arrays and Hashes? In fact, learn Ruby as much as you can.
Answering your question,
/home.html.erb
<%= form_tag "/static_pages/home", :method => 'post' do %>
<p>
<%= text_field_tag "search[name]", params.has_key?("search") && params[:search].has_key?("name") ? params[:search][:name] : "" %>
<%= submit_tag " Search Database Records " %>
</p>
<% end %>
/models/ciir.rb
def self.search(search)
if search
find(:all, :conditions => ["name LIKE '%?%'", search[:name]])
else
find(:all)
end
end
So I modified your form, and told RoR about search params containing data for name.
params is a Hash (which is a key-value pair) having key named search, which further is a Hash having key named name.
The same principle is followed in the model code. We passed the Hash of key search to the function and in there, used the value of key named name.
I also updated the url in form_tag, to point it to home action of your controller. Assuming that you have added it to your routes.rb file, it usually follows the pattern controller_name/action_name or the function name action_name_controller_name_path or action_name_controller_name_url. Run rake routes command at your root directory to list out all paths in your application.
Also note, I used POST method instead of original GET. You may wish to use GET here, so please change it back.
I hope this works.
I found no error in your code. the url changed to ciirs?utf8=✓&search=&commit=+Search+Database+Records+ is normal. submit_tag generates a button named "commit" defaultly, it will be parsed in the params. I see you add :name => nil , it will fix the problem, the other part of your code needn't to be modified. I copied your code and tested it, it ran smoothly.
Related
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
This is probably a very simple fix but I've been unable to find an answer just yet.
My application has orders and tasks. Orders have many tasks. When a user clicks new task in the show order view, it passes the order.id:
<%= link_to "New Task", new_task_path(:order_id=> #order.id) %>
The url shows:
/tasks/new?order_id=1
I just don't know how to extract this and use it in my form? I have tried:
<%= f.text_field :order_id, :value => #order_id %>
But it's not working.
You can do:
<%= f.text_field :order_id, :value => params[:order_id] %>
Alternately, capture the value (with params) in the controller and assign it to #order_id there.
You are doing this wrong, which is a big deal in Rails where convention-over-configuration is such an important ideal.
If an order has many tasks, your route should look like this:
/orders/:order_id/tasks/new
And your routes should be configured thusly:
resources :orders do
resources :tasks
end
You should [almost] never find yourself passing around record ids in the query string. In fact, you should almost never find yourself using query strings at all in Rails.
So let's say I have a form which is being sent somewhere strange (and by strange we mean, NOT the default route:
<% form_for #form_object, :url => {:controller => 'application',
:action => 'form_action_thing'} do |f| %>
<%= f.text_field :email %>
<%= submit_tag 'Login' %>
<% end %>
Now let's say that we have the method that accepts it.
def form_action_thing
User.find(????? :email ?????)
end
My questions are thus:
How can I make the object #form_object available to the receiving method (in this case, form_action_tag)?
I've tried params[:form_object], and I've scoured this site and the API, which I have to post below because SO doesn't believe I'm not a spammer (I'm a new member), as well as Googled as many permutations of this idea as I could think of. Nothing. Sorry if I missed something, i'm really trying.
How do I address the object, once I've made it accessible to the method? Not params[:form_object], I'm guessing.
EDIT
Thanks so much for the responses, guys! I really appreciate it. I learned my lesson, which is that you shouldn't deep-copy an object from a form, and that the parameters of a form are actually included when you submit it.
I will admit it's sort of disheartening to not know stuff that seems so obvious though...
you need to pass the "id" of your "#form_object" in the url and then lookup that object (assuming you have a model and using ActiveRecord)
It depends on how do you set up your routes. If you're using the default /:controller/:action/:id route, you can pass it as a parameter in the URL. Note that not the whole #form_object can/should be passed, but it's id or some other attribute to identify it instead. In this case, you should make your URL:
<% form_for #form_object, :url => {:controller => 'application',
:action => 'form_action_thing', :email => some_email} do |f| %>
<%= f.text_field :email %>
<%= submit_tag 'Login' %>
<% end %>
And in your controller
def form_action_thing
#user = User.find_by_email(params[:email])
end
You can pass parameters through the url, but when submitting a form the only thing that should (probably) be passed through the url is the record id for a RESTful record.
And it appears you didn't find out yet where your form data can be found in the params.
So
All the data from your form should end up in params[:form_object]. The actual value for :form_object is selected by Rails, it's probably coming from the object's class (too lazy to look that up right now)
In any case, you can easily find out where your form values are submitted by looking at your console/log output. All the params for each requests are dumped there.
The form fields will be inside the params like params[:form_object][:email] - each field that is submitted has an entry corresponding to the field name.
The params hash not contain all the original values from your #form_object. There will be only those values that you included in the form.
If you need to pass non-editable values to the controller with your form, use hidden_field(s) These will be submitted with the form, but are not visible to the user.
I built a basic search form that queries one column in one table of my app. I followed episode 37 Railscast: http://railscasts.com/episodes/37-simple-search-form
Here's my problem. I want to display the search query that the user makes in the view that displays the search results. In my app, the search queries the zip code column of my profile model, and returns a list of profiles that contain the right zip code. On the top of the list of profiles returned from the search, I want it to say "Profiles located in [zip code that was queried]."
I'm sure I can do this because the queried zip code gets passed into the url displaying the results. So if the url can pick it up, there must be some way to display it in the view on the page as well. But I don't how.
Please keep in mind that I'm not using any search pluggins and I don't want to use any for now. This is my first app, so I don't want to add complexity where it's not needed.
Per Ryan's instructions in the Railscast, here's my setup:
PROFILES CONTROLLER
def index
#profiles = Profile.search(params[:search])
end
PROFILE MODEL
def self.search(search)
if search
find(:all, :conditions => ['zip LIKE ?', "%#{search}%"])
else
find(:all)
end
end
PROFILE/INDEX.HTML.ERB
<% form_tag ('/profiles', :method => :get) do %>
<%= text_field_tag :search, params[:search], :maxlength => 5 %>
<%= submit_tag "Go", :name => nil %>
<% end %>
The search itself is working perfectly, so that's not an issue. I just need to know how to display the queried zip code in the view displaying the results.
Thanks!
Just set it to an instance variable and use that.
def index
#search = params[:search]
#profiles = Profile.search(#search)
end
In your view, you can reference #search.
Also, as a friendly tip, please use an indent of 2 spaces for Rails code. It's the standard way to do it, and others who are reading your code will appreciate it.
so i have this code:
<% form_tag(:action => 'find') do%>
Product name:
<%= text_field("cars_", "name", :size => "30") %>
<input type ="submit" value="Find"/>
<%end%>
upon pressing the button I want it to complete the method (def find) found in the controller but its requesting the html.erb file:
Template is missing
Missing template cars/find.erb in view
path H:\Documents and
Settings/owner/My
Documents/NetBeansProjects/RailsApplication5/app/views
in the find def (found in controller)
def find
#car = Car.new(params[:car_])
end
What is the last line of your find method? Generally, if you don't specify the template to render in your controller method, Rails attempts to find a template with the same name as the method. That is why it is saying it can't find cars/find.erb. Without seeing the code in your find action, it is hard to give a better answer.
Your find method should be doing some searching, not initializing with the parameters. I recommend checking out something like thinking sphinx or searchlogic if you want to do searching.
I believe that your code is executing the find action. However, after it finds the car object, it needs to write that into a template that shows the results of your search. By convention, rails looks for a file called find.html.erb in the view folder for that controller. So, the error message you are seeing means that Rails has executed the line of code in your action and is now trying to generate some HTML to send back to the browser
If you create a simple file in the view folder for that controller with contents:
<%= #car.name %>
You should see the results.
However, your code is a bit confusing to me as I don't know why a find method would create a new Car object. I would expect something like this:
def find
#car = Car.find_by_name(params[:name])
end
I would also expect that your form would be more like:
<% form_tag(:action => 'find') do%>
Product name:
<%= text_field_tag("name", :size => "30") %>
<%= submit_tag "find" %>
<%end%>