Rendering Rails from tag - ruby-on-rails

I have my form_tag set up as follows:
<% Rating.find(:all, :conditions => ["recommendation_id = ? and rating_set = ? and product_id = ?", rec.id, params[:rating_set_id], params[:product_id]]).each do |rate| %>
<%= text_field_tag "recommendation_ratings[#{rec.id}][notes]", "#{rate.notes}", :id => "rec_note_text", :placeholder => 'Enter Notes..'%>
<% end %>
This works when the find conditions are met, however before the form is submitted, the recommendation_id is not persisted to the DB, so this find method does not return anything, and this causes my form tag not to render. It only render when all conditions of the find are met. How can I render my form regardless is the find condition is met?

You are using view/controller in a wrong way.
You should define new partial called _rating.html.erb
in there your form_tag (please replace with valid values, I have just put as an example)
<%= text_field_tag "recommendation_ratings[#{id}][notes]", "#{notes}", :id => "rec_note_text", :placeholder => 'Enter Notes..'%>
then, wherever you are rendering that list of Ratings, put for example in ratings/show.html.erb
<%= render #ratings%>
and in Ratings_controller you should put:
define show
#ratings = Ratings.find_all_with_conditions
end
and in model Rating.rb you should put:
define self.find_all_with_conditions
Rating..find(:all, :conditions => []) #put your logics here for finding all
end
I have just wrote just as an example how you should organize it, and I have not looked to put all valid parameters, I have put just for you to see how to organize you view.
I hope it will help.

Related

How should I make this routing RESTful?

For RESTful purpose, I made my routing just like this:
routes.rb
match 'shops/:sort/:genre/:area', :to => 'shops#index'
But what if genre was empty?
Isn't it going to redirect to example.com/shops/newest_first//california?
How can I solve this kind of routing and parameters problem?
Can anyone show me good example?
view
<%= form_tag shops_path, :method => :get do %>
<%= select_tag :sort, options_from_collection_for_select(Sort.all, 'id', 'name', params[:sort]), :prompt => "Newest first" %>
<%= select_tag :genre, options_from_collection_for_select(Genre.all, 'id', 'name', params[:genre]), :prompt => "all" %>
<%= select_tag :area, options_from_collection_for_select(Area.all, 'id', 'name', params[:area]), :prompt => "all" %>
<% end %>
Another View
While restful routing is the most intuitive and conventional, it does not always fit our needs.
In your case I'd suggest using query parameters instead of a strict restful route.
example.com/shops will receive 3 query parameters: sort, genre and area, so a URL may look like example.com/shops?area=california&sort=newest_first
The in the index action of you controller you can query for the existence of these parameters in the following manner:
def index
if !params[:sort].blank?
#shops = #shops.sort(params[:sort])
end
if !params[:area].blank?
#shops = #shops.where(:area => params[:area])
end
.
.
.
end
This way you are well protected against missing parameters in your controller, but still you are able to supply whatever data the user requests.
On a side note: be sure to check that the params hash you're using contains only values you are willing to accept.

Handling an undefined variable

I render a partial in one view:
<%= render 'video', :video => #video, :video_id => 'video_show_id' %>
and have this code in the partial:
<% if video_id %>
<%= link_to "video", video.video_url, :class => "oembed", :id => video_id %>
<% else %>
<%= link_to "video", video.video_url, :class => "oembed" %>
<% end %>
The problem is that this partial gets rendered in a number of places in my app, and in those other views I do not want to pass :video_id into the partial. Therefore my app throws an error that video_id is undefined. I could pass :video_id => "" into the partial in the other views, but since the partial is rendered in many places, that is kind of a pain. Is there a simpler way to handle this?
Try defined? and not that it really matters but it's actually an operator.
<% if defined? video_id %>
I think the better way to handle this is to create a helper that then manages the values of variables that need to fed to a partial. Something like:
module VideoHelper
def show_video(video, options = {})
options[:id] ||= ""
render 'video', :video => video, :video_id => options[:id]
end
end
Now, instead of having to have that long render partial line in your view, you get to shorten it to a show_video call.
Also, I've found that in the long term, this allows for a lot more flexibility and I have to think a lot less about what variables the partial needs at this time and whether or not they are defined.
Change the check to <% if defined? video_id %>

Rendering an Edit partial while selected a defaulted value

I have a partial in my rails app that loads the vote form (It's just a select with numbers ranging from 1-5). I'm now making another partial that loads up if the user has already voted it's suppose to be an EDIt partial where you get selected the value that you voted and if you wanted to you could change it. But for some reason is not working, here's the code for it.
#Finds the vote by passing the user and the article
<%= #vote = Vote.find_vote_by(current_user,#article) %>
#Renders the partial with the vote variable loaded up with the vote that was found
<%= render :partial => "votes/edit_vote", :locals => {:vote => #vote} %>
And this is the partial
<% form_for(vote, :url => {:controller => 'votes', :action => 'edit'}) do |f| %>
<%= error_messages_for :vote %>
<p><%= f.hidden_field :article_id %></p>
<p>
<%= f.label :value, "Value for the vote: "%>
<%= f.select :value, {"1" => "1","2" => "2","3" => "3","4" => "4", "5" => "5"}, :selected => vote.value %>
</p>
<p>
<%= f.submit "Cloud-it!" %>
</p>
<% end %>
But for some reason the vote variable is not containing anything not the article_id, nor the value method, any ideas?
EDIT1: Per request here's what's debug #vote is outputting (It it indeed a sane value)
attributes:
created_at: 2010-09-02 14:39:04
updated_at: 2010-09-02 14:39:04
id: 1
value: 4
article_id: 1
user_id: 1
attributes_cache: {}
EDIT2
I tried clearing the partial code, in order to output this:
<%= debug #vote%>
<%= #vote.value %>
If i debug #vote it comes out perfect, will all the attributes and such. But whenever i add the second line it, It's not working it tells me that there's no .value, i tried .id, .article and nothing is as if it didn't exist. Any ideas?
EDIT3
Here's the vote by
named_scope :find_vote_by, lambda {|user,article| {:conditions => {:user_id => user, :article_id => article}}}
The reason behind it, it's that named scopes actually return named scopes, and you can't access the attributes just like it were a Vote class. I fixed this by changing the way to retrieve the vote and just forgetting about using that named scope. I accomplished it by using:
<% #vote = current_user.votes.find_by_article_id(#article)%>
which is a Rails method and actually returns a vote class. Then i just passed it to the partial and the magic worked!
Thank you so much to thenduks, without his help i couldn't had done it.
So first thing to fix is this line:
<%= #vote = Vote.find_vote_by(current_user,#article) %>
Should be:
<% #vote = Vote.find_vote_by(current_user,#article) %>
The former is for outputting in ERB and the latter is for executing arbitrary ruby code.
Next, put a line below that like so:
<%= debug #vote %>
And make sure it's a sane value. If not, paste the definition of your Vote class method find_vote_by.
EDIT: In that case it's probably just because using :locals => {...} makes instance variables, so you want #vote in your partial with the form.

Help with rails association

Ok guys, so I'm making a scheduler.
So I have two tables so far,
Shows with "title:string" and "description:text" and I also have
ShowTime; with "show_id:integer", "day:string", and "show_time:time".
I did the has_many, and belongs_to, I honestly do not know where to go from here on,
I want a user to be able to add the times when creating a new show. What would I do? I was looking at some rails associations documentations, seems like I would be making something like,
#showtime = #shows.showtimes.create(:show_id => show.id, :day => DAY, :show_time => TIME)
Notice I put just DAY and TIME, because I also honestly don't know how I'll fetch this data.
It really depends on your interface. But for simplicity, let's assume you provided two select boxes for selecting day and time, and have to add ShowTime one by one.
And assume you have rest resources:
map.resources :shows do |show|
show.resources :show_times
end
The form: (given a #show object created already)
<% form_for #show_time, :url => show_show_time_path(#show) do |form| %>
<%= form.label :day %>: <%= form.select :day, [["Mon", "mon"], ["Tue", "tue"]], {} %>
<%= form.label :show_time %>: <%= form.select :show_time, [["Slot 1", "09:00"]], {} %>
<% end %>
You should provide your best way to generate the day & show_time arrays. They are in the following structure:
[["Text", "value"], ["Text", "value"]]
which will generate something like:
<option value="value">Text</option>
After the form is submitted, in your create action:
def create
#show = Show.find params[:show_id] # this params[:show_id] is from the rest resource's path
#show_time = #show.show_times.build(params[:show_time]) # this params[:show_time] is from the form you submitted
if #show_time.save
flash[:notice] = "Success"
redirect_to show_show_time_path(#show, #show_time)
else
flash[:notice] = "Failed"
render :action => "new"
end
end

Ruby on Rails Country/State Select Enigma

I am trying to implement something seemingly very simple, and I have been beating my head against it for days at this point.
My desired end result is a Country select drop-down, tied to a State select drop-down, in such a way that when a given country is selected, IF states are known THEN those states are displayed in a select drop down, and if NO states are known for that country, then a text field is displayed instead.
I feel like I am almost there. At this point the interface will actually generate that list of states based on the persons' country, except it is refusing to update the drop-down dynamically.
The portion of my view where country and state location is gathered looks like:
# _person_setup.html.erb
<td>
<%= f.label :country, 'Select your country' %>*<br />
<%= f.select :country, Carmen::country_names, {},
{:style => 'width: 200px',
:id => 'country_select',
:onchange => remote_function(
:url => {:action => 'update_states'},
:with => "'country='+value")} %>
</td><td>
<p>
<div id="states_div">
<%= render :partial => 'states',
:object => Carmen::states(
Carmen::country_code(
#person.country)),
:locals => {:form => f} %>
</div>
</p>
</td>
The partial being referenced in the DIV is as follows:
# _states.html.erb
<% unless states.nil? or states.empty? %>
<%= form.label :state, 'Select your state' %>*<br />
<%= form.select :state, states.collect{|s| [s[0], s[0]]} %>
<% else %>
<%= form.label :state, 'Please enter state or province' %>*<br />
<%= form.text_field :state %>
<% end %>
Finally, the controller code which is intended to update the list of states dynamically:
def update_states
puts "Attempting to update states..."
q = params[:country]
states = Carmen::states(Carmen::country_code(q))
puts "Country = #{q}, states = #{states.collect{|s| s[0]}.join(", ")}."
render :update do |page|
page.replace_html "states_div",
:partial => 'states',
:object => states,
:locals => {:form => form_for(#person)}
end
puts "OK"
end
Now, this code is being called at the proper time and generating the appropriate lists of states. For example, when the user clicks Australia, "Attempting to update states... Country = Australia, states = Australian Capital Territory, New South Wales, Northern Territory, Queensland, South Australia, Tasmania, Victoria, Western Australia" shows up in the server process. However it doesn't update the page, and won't print the "OK" at the end. In short the line which is failing is undoubtedly
page.replace_html "states_div",
:partial => 'states',
:object => states,
:locals => {:form => form_for(#person)}
Note that replacing this line with
page.replace_html 'states_div', "<b>is it working</b>"
properly replaces the div, but of course not with anything useful.
Can someone help me understand what is going on here?
It looks like you're assuming that the #person variable is still available from your original action. This could be set up by a filter for the current person but you don't show that in your question.
If you do need to lookup the #person again you'll have to pass the id through in your remote_function I think.
Ryan Bates has a Railscast that shows how to select a category for a product or create a new category by typing the name. It sounds like a similar scenario to what you have, so you might want to check it out: Create Model Through Text Field.
This took me a full day to figure out something that would at least "work". I am also using Carmen and also messing with the select tag in a form_for model form (actually, fields_for nested within forms_for...which adds additional complications).
I would think there is a better solution but this worked for me. The select needs to be referenced by the form but the options don't. Thus, first time through, I use the Carmen state_select method which populates the select tag correctly and all the nested options tags. The second time through, I just replace the options. Take a look:
In the view, I chose to use an observe_field method since I do other things besides update the states (some other localization changes) but this should work for remote_function and others, too:
<%= address_form.country_select :country, {:prompt => "--Select One--"} %>
Don't be confused by the id (user_address_attributes_country) it is just my silly forms_for/fields_for implementation)
<%= observe_field :user_address_attributes_country, :url => { :action => :changecountry }, :with => 'new_country' %>
<%= address_form.state_select :state, #user.address.country, {:prompt => "--Select One--"}, :style => 'width: 90px' %>
Then in my controller, it just looks like this:
def changecountry
c = params[:new_country]
respond_to do |format|
format.html
format.js {
render :update do |page|
page['user_address_attributes_state'].innerHTML = \
"<option>--Select One--</option>" + state_options_for_select(nil, c)
end
}
end
end
Note: state_options_for_select is also from Carmen. I could not get it to work unless I put it inside the respond_to block where I guess the view helpers are available. Also, I hard code user_address_attributes_state which is my nested id generated from the form_for/fields_for address_form.state_select rendering call in the view.
I hope this helps. If anyone can do it better, believe me, I'm all ears. I'll change the design in time...but needed something that just worked today and this was the best I could figure out in a limited time.

Resources