A model named 'book' with attributes 'name' and 'id' is given. How can i use this collection select to call the show-action of a certain book? The one code mentioned below returns the following error message:
Couldn't find Book with ID=book_id
<% form_tag(book_path(:book_id)), :method => :get do %>
<p>
<%= label(:book, :id, 'Show Book:') %>
<%= #books = Books.find(:all, :order => :name)
collection_select(:book, :id, #books, :id, :name)
%>
</p>
<p>
<%= submit_tag 'Go' %>
</p>
<% end %>
book_path is generated once only, for the form tag itself. It won't be updated whenever your selection changes.
When you submit that form, it's going to request the following URL:
/books/book_id?book[id]=5
Since your book_path thinks book_id is the ID number you wanted, it tries to look that up. You could do what you want you by changing the code in your controller from:
#book = Book.find(params[:id])
to:
#book = Book.find(params[:book][:id])
But it kind of smells bad so be warned.
You can create a new route that is not based on the id, like
get 'books/show' # put this above your "resources :books"
and change your form to
<% form_tag books_show_path, :method => :get %>
Related
I'm trying to implement a two search form_tag on a the same page, each search form is placed inside dynamic bootstrap tabs. The first one which is working is basic a search form with one field. The second one which is not working has two fields, one is the same search method as the first and the other I'm trying to get the address from the other_location field and via params[:other_location].
With the current setup the other_location field form the second form does not appear!
Both of the forms are inside partials and I am rendering them inside two dynamic bootstrap tabs like this:
<%= render 'pages/search' %>
<%= render 'pages/search_other' %>
<%= form_tag search_items_path, :method => "get" do %>
<%= text_field_tag :search, params[:search], autofocus: true,
class: "search-query search_size",
placeholder: "Enter product to search" %>
<%= submit_tag "Search", name: nil, :style => "display: none;" %>
<%end%>
<%= form_for :search_other_path, :method => "get" do |form| %>
<%= form.text_field :search, autofocus: true,
class: "search-query search_size",
placeholder: "Enter keyword to search" %>
<% form.fields_for :other_location_path, :method => "get" do |f| %>
<%= f.text_field :other_location, class: "search-query search_size",
placeholder: "Enter address to search" %>
<%= form.submit "Search", name: nil, :style => "display: none;" %>
<%end%>
<%end%>
model
def self.search(search)
return where("0=1") if search !~ /\w{4}/
where("lower(title) LIKE lower(:term)", term: "%#{search}%")
end
routes.rb
get 'search' => 'pages#search', as: 'search_posts'
get 'search' => 'pages#search_other', as: 'search_other'
get 'search' => 'pages#other_location', as: 'other_location'
controller:
def search_other
if params[:search]
#posts = Post.near(other_location,10).search(params[:search]).page(params[:page])
else
#posts = []
end
end
def other_location
other_location = params[:other_location]
if params[:other_location]
Geocoder.search(params[:other_location])
end
end
def search
if params[:search]
#posts = Post.near(action,10).search(params[:search]).page(params[:page])
else
#posts = []
end
end
On your route file:
get 'search/other' => 'pages#search_other', as: 'search_other'
get 'search' => 'pages#search_other', as: 'search_other_items'
both GET requests are going to your pages_controller.rb #search_other method. So even if you have the two form_tags sending the data to different paths (search_other_path, and search_other_items_path) it would be going to the same controler method - which is redundant.
On your actual HTML you have two form tags:
<%= form_tag search_items_path, :method => "get" do %>
and
<%= form_tag search_other_items_path, :method => "get" do %>
You have not mentioned search_items_path in your routes, so I have no idea where that's pointing to. Likely its a proper controller that works since you mentioned the first form was the only one working.
Now, your mentioned controller only has a search method. So to start you are looking at the wrong controller. You should be looking at the controller methods being referenced by the form's action.
In this case, the second form is sending it's request to search_other_items_path which according to your routes, its pointing to pages_controller.rb -> #search_other method.
You should edit your question to include code that is actually relevant. Maybe then I can actually help.
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.
Okay so I am quite new to Rails and am trying to do the following without success:
I have an Object (from my Active Record) containing a project, which contains n sub-projects, which contain n tasks. Now for each of these I want a partial view.
So I render from the project view the sub-project with the following code:
<%= render(:partial => 'subproject', :collection => #project.sub_projects) %>
Within my sub-project partial view called _subproject.rhtml (adding the code to a good ol Rails 1.2.3 project), so I can access the data like this:
<%= subproject.name %>
That will print out the name alright but when I try to generate a textfield this won't work:
<%= text_field 'subproject', 'name' %>
But this will:
<%= text_field 'subproject', 'name', :value => subproject.name %>
What am I doing wrong?
Edit: Changed title due to my problem is not passing the value but displaying it within a form field.
Edit2: As requested my controller code:
#project = Project.find(params[:id])
You can write this:
<%= render(:partial => 'subproject', :collection => #project.sub_projects) %>
as
<%= render :partial => #project.sub_projects %>
This will render every sub project with the sub_projects/_sub_project.html.erb partial. A little shortcut.
This:
<%= text_field 'subproject', 'name' %>
Says create a text_field called: subproject[name], but doesn't give it a value. You need to pass the value you want to set (the code that works).
The more idiomatic way of doing this now is with form_for:
<% form_for #subproject do |f| %>
<%= f.text_field :name %>
<% end %>
Or if you're using formtastic (https://github.com/justinfrench/formtastic), which is fantastic, you'd write:
<% semantic_form_for #subproject do |f| %>
<%= f.input :name %>
<% end %>
I hope this helps!
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)
One of the things I'm doing includes several links on the show view. For instance, I have a link (or button) for "Accepting", and another one for "Rejecting". Click on Accept, and the model updates the is_accepted field as true, click on Reject, and the is_accepted field is false.
Now, how best do I handle this? In ASP.NET, I would have simply created a LinkButton and written a handler, but Rails doesn't work that way, so I'm trying to figure out how to essentially replicate what a LinkButton would do.
Right now, I'm coding two forms on the same view, nearly identical, that look like this:
<%= form_for #thing do |f| %>
<%= hidden_field_tag 'thing[is_accepted]', '1' %>
<%= f.submit "Accept" %>
<% end %>
<%= form_for #thing do |f| %>
<%= hidden_field_tag 'thing[is_accepted]', '0' %>
<%= f.submit "Reject" %>
<% end %>
This feels weird to me, but I can't seem to find anything that says this is the wrong way to do it.
I could, I assume, dry things up by using a partial and/or a helper method, but I wanted to make sure I'm on the right track and not doing something totally wrongly.
You can give your submit tag a name.. ie
<%= form_for #thing do |f| %>
<%= hidden_field_tag 'thing[is_accepted]' %>
<%= f.submit "Accept", :name => 'accept' %>
<%= f.submit "Reject", :name => 'reject' %>
<% end %>
Then you can detect the name in params[] and skip the '1'/'0' value.
I think you're going about it the right way. One way to clean up your forms is by using the model form helpers all the way through, so you'd end up with something like
<%= form_for #thing do |f| %>
<%= f.hidden_field :accepted, :value => true %>
<%= f.submit "Accept" %>
<% end %>
<%= form_for #thing do |f| %>
<%= f.hidden_field :accepted, :value => false %>
<%= f.submit "Reject" %>
<% end %>
But other than that, it looks like the right way to go about it. I would suggest against creating new methods to do this, because you're not doing anything outside of normal web requests (updating a model in this instance).
Using the submit tag as the switch and detecting it in params[] is also a good way, but I usually prefer to keep my controllers as vanilla as possible. In the end, both of these ways would end up with the same amount of 'stuff' in the UI, so whichever style you'd rather use should be fine.
Depending on how you want your UI to work you might consider link_to_remote (part of the prototype helper) - you can specify an action, params etc, and have it return some JS that gets run.
If you're using map.resources in your routes.rb you should be able to do something like this:
map.resources :things, :member => {:accept => :get, :reject => :get}
Then in your controller:
def accept
#thing = Thing.find(params[:id])
#thing.is_accepted = true
#thing.save
end
def reject
#thing = Thing.find(params[:id])
#thing.is_accepted = false
#thing.save
end
And finally in your view:
<%= link_to 'Accept', accept_thing_url(#thing) %>
<%= link_to 'Reject', reject_thing_url(#thing) %>
Or if you are using Ajax:
<%= link_to_remote 'Accept', :url => accept_thing_url(#thing) %>
<%= link_to_remote 'Reject', :url => reject_thing_url(#thing) %>