Rails 3.2.13 & ERB
I am trying to get send some link_to items to a partial. I am sending in a title to the partial successfully as below.
<%= render :partial =>'form',
:locals => {:page_title => t(:'<h2>Editing Feature</h2>')}
What I dont like is that I am currently doing this:
<%= link_to 'Show', #feature %> |
<%= link_to 'Back', features_path %>
as part of the primary page. I would like to take this codeblock and send it to the partial for rendering there. The primary reason is the simple_form is defined in the partial and I have a well that contains everything on that page. Except for the two link_to items down on the bottom of the page. If I could pass them into the partial somehow (I assume as a code block) then I can decide where to place them and how to render them in the form itself instead of kind of as an afterthought.
Thanks.
Typically we use partials to break off HTML chunks into separate modular components and reduce repetition. Partials have the same variable context as the template that rendered them, so as-is, you wouldn't have any trouble simply relocating your links to your partial and everything should just work.
I think the better practice, however, would be to pass your instance variable as a local to reduce coupling with your controller. Something like:
Your view:
<%= render :partial =>'form',
:locals => {:page_title => t(:'<h2>Editing Feature</h2>'),
:feature => #feature} %>
_form.html.erb:
<%= link_to 'Show', feature %> |
<%= link_to 'Back', features_path %>
This way, if you were to render the partial elsewhere in your application you don't need to have an instance variable handy. An example situation where this could be useful would be looping through multiple "features" (a la an index view) and spitting out the relevant HTML as defined in the partial.
Related
I'm having trouble getting traction on what the general ways data gets passed around from and is made available to partials.
For example:
I have a controller handing off an instance variable to a template that renders a partial:
static_pages_controller.rb:
def home
#feed_items = current_user.feed
end
home.html.erb:
<%= render 'shared/feed' %>
_feed.html.erb:
<%= render #feed_items %>
Now, inside my User model is an instance method that reaching into the database to get her posts:
user.rb:
def feed
Micropost.where("user_id = ?", id)
end
So somehow because Micropost.where(...) returns a collection of microposts is that how Rails knows to go from _feed.html.erb to another partial where the <li> is defined for how microposts want to be defined?
_micropost.html.erb:
<li id="micropost-<%= micropost.id %>">
<%= link_to adorable_avatar_for(micropost.user, size: 50), micropost.user %>
</li>
And also is it just a convention that because I'm really handling a collection of microposts that Rails knows to give the micropost variable?
Your questions are answered in the Ruby on Rails Guides on Layouts and Rendering. It's worth reading the information on partials that comes before the quoted passages below as well:
Every partial also has a local variable with the same name as the
partial (minus the underscore). You can pass an object in to this
local variable via the :object option:
<%= render partial: "customer", object: #new_customer %>
Within the customer partial, the customer variable will refer to
#new_customer from the parent view. (Earlier the Guide instructs that to specify other options for render(), e.g. object:, you have to explicitly specify partial: and the name of the partial.)
If you have an instance of a model to render into a partial, you can
use a shorthand syntax:
<%= render #customer %>
Assuming that the #customer instance variable contains an instance of
the Customer model, this will use _customer.html.erb to render it and
will pass the local variable customer into the partial which will
refer to the #customer instance variable in the parent view.
3.4.5 Rendering Collections
Partials are very useful in rendering collections. When you pass a
collection to a partial via the :collection option, the partial will
be inserted once for each member in the collection:
index.html.erb:
<h1>Products</h1>
<%= render partial: "product", collection: #products %>
_product.html.erb:
<p>Product Name: <%= product.name %></p>
When a partial is called with a pluralized collection, then the
individual instances of the partial have access to the member of the
collection being rendered via a variable named after the partial. In
this case, the partial is _product, and within the _product partial,
you can refer to product to get the instance that is being rendered.
There is also a shorthand for this. Assuming #products is a collection
of product instances, you can simply write this in the index.html.erb
to produce the same result:
<h1>Products</h1>
<%= render #products %>
Rails determines the name of the partial to use by looking at the
model name in the collection. In fact, you can even create a
heterogeneous collection and render it this way, and Rails will choose
the proper partial for each member of the collection:
index.html.erb:
<h1>Contacts</h1>
<%= render [customer1, employee1, customer2, employee2] %>
customers/_customer.html.erb:
<p>Customer: <%= customer.name %></p>
employees/_employee.html.erb:
<p>Employee: <%= employee.name %></p>
In this case, Rails will use the customer or employee partials as
appropriate for each member of the collection.
In the event that the collection is empty, render will return nil, so
it should be fairly simple to provide alternative content.
<h1>Products</h1>
<%= render(#products) || "There are no products available." %>
I have submit button and i want to redirect in another URL (hard coded) this URL
https://www.ccavenue.com/shopzone/cc_details.jsp
my code :
<%= form_tag #ccavanue do |f| , url => "https://www.ccavenue.com/shopzone/cc_details.jsp", :html => :method => "put" %>
<%= hidden_field_tag :my_field, #MerchantId, :id => 'merchant_id' %>
<%= submit_tag "Click Me" %>
<% end %>
i want to redirect another website URL with this submit button . please guided me.
Change your code to following:
<%= form_for #ccavanue, url: "https://www.ccavenue.com/shopzone/cc_details.jsp" do |f| %>
<%= f.hidden_field :my_field, #MerchantId, :id => 'merchant_id' %>
<%= f.submit "Click Me" %>
<% end %>
In Rails a form is designed to create or update a resource and reflects the identity of the resource in several ways:
The url that the form is sent to (the form element's action attribute) should result in a request being routed to the appropriate controller action (with the appropriate :id parameter in the case of an existing resource),
Input fields should be named in such a way that in the controller their values appear in the appropriate places within the params hash, and
For an existing record, when the form is initially displayed, input fields corresponding to attributes of the resource should show the current values of those attributes.
In Rails this is achieved by creating form using form_for where:
If we want to create any object we use POST method within url and PUT method if we are trying to update an existing record.
Rails framework is smart enough to use POST or PUT method by itself looking at the url of the form. So in this case we need not use method parameter within form_for url.
Probably you can start with Michael Hartl's tutorial
I have an STI relationship where a conversation is composed of both messages and images.
Now when I go to render them i use:
<%= render conversation %>
which works perfect. It finds the given template for the given object and renders it.
Now for my mobile site I want to use the same thing only now it should find say:
/mobile/message/_message.html.erb
instead of
/message/_message.html.erb
So in my controller i said:
if mobile?
prepend_view_path "mobile"
end
Which does get called, and it "prepends my view path" which i can see is working when i do:
raise view_paths.inspect
However now when i do my
<%= render conversation %>
It is still looking in the default location i.e. /views/ for the partial
Well, this should work, but it is distressingly inelegant:
<% conversation.each do |c| %>
<% c_class = c.class.to_s.downcase.underscore %>
<%= render :partial => "mobile/#{c_class}/#{c_class}", :object => c %>
<% end %>
UPDATED CODE at the bottom
I am creating a story voting app via Simply Rails 2 book. I am getting this error when I click the button to vote up a story:
No route matches "/stories/4-pure-css-icons-showcase"
My routing file looks like this:
Shovell::Application.routes.draw do
get "votes/create"
root :to => "stories#index"
resources :stories do
resources :votes
end
end
votes_controller.rb:
class VotesController < ApplicationController
def create
#story = Story.find(params[:story_id])
#story.votes.create
end
end
create.rsj :
page.replace_html 'vote_score', "Score: #{#story.votes.size}"
page[:vote_score].visual_effect :highlight
show.html.erb:
<h2>
<span id="vote_score">
Score: <%= #story.votes.size %>
</span>
<%= #story.name %>
</h2>
<p>
<%= link_to #story.link, #story.link %>
</p>
<div id="vote_form">
<%= form_tag :url => story_votes_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
</div>
story.rb :
class Story < ActiveRecord::Base
validates_presence_of :name, :link
has_many :votes
def to_param
"#{id}-#{name.gsub(/\W/, '-').downcase}"
end
end
I've been working through a number of other errors before this having to do with deprecated code and so forth, so I feel somewhat lost at the moment. It seems like it should just be a routing a issue, but since I've been working through AJAX errors that also have to do with the vote function I wanted to post those files just in case it was more than routing.
It says no route matches "/stories/4-pure-css-icons-showcase" but when I visit "/stories" (my root) and click on the link to take me to "/stories/4-pure-css-icons-showcase" it works fine, however after clicking on the vote button I get this error. As you could probably tell after reading the code, it is suppose to update the vote count and do a :highlight via ajax.
UPDATE:
Changed code (all changes are per Sam's advice):
routes:
Shovell::Application.routes.draw do
resources :votes
root :to => "stories#index"
resources :stories do
resources :votes
end
show.html.erb:
<div id="vote_form">
<%= form_tag :url => new_story_vote_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
</div>
votes_controller.rb
class VotesController < ApplicationController
def create
#story = Story.find(params[:story_id])
#story.votes.create
respond_to do |format|
format.html
format.js
end
end
The problem is still exactly the same, but I think (read: hope) we are making progress!
The scenario: My index (/stories) page randomly displays a story from the database, when you click the link it takes you to the story's internal page (ex. /stories/2-sitepoint-forums) on this page it displays the number of votes the story has and has a button to vote for it. When you click the vote button it is suppose to use ajax to update the #story.vote.size and use a :highlight visual effect. However, the problem is that when you click the vote button the page changes to a "Routing Error" page which displays:
No route matches "/stories/2-sitepoint-forums"
Its weird to me because you can in fact be routed to that address and you are from the link on the first page...
Here is the error in the console:
Started POST "/stories/2-sitepoint-forums?url=%2Fstories%2F2-sitepoint-forums%2F
votes%2F2-sitepoint-forums&remote=true" for 127.0.0.1 at 2010-11-08 16:30:17 -08
00
ActionController::RoutingError (No route matches "/stories/2-sitepoint-forums"):
Rendered C:/Ruby192/lib/ruby/gems/1.9.1/gems/actionpack-3.0.0.rc2/lib/action_dis
patch/middleware/templates/rescues/routing_error.erb within rescues/layout (1.0m
s)
Im not sure if this is any more telling, but I thought I'd add it incase.
New:
I have not been able to solve this problem as of yet. Because I still don't feel like I completely understand the issue I have decided to move over to the Ruby on Rails 3 Tutorial Book online and see if I can't figure it out while working through it. Since I was planning to do it next anyway (I have plans to combine both apps later) it appears now is the time.
<%= form_tag :url => new_story_vote_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
That should send it to the create action.
def create
#story = Story.find(params[:story_id])
#story.votes.create
respond_to do |format|
format.html
format.js
end
end
And that should take care of your ajax.
take this get "votes/create" out of your routes
and add this
map.resources :votes
I'm not familiar with using form_tag and :remote (as I normally just write jQuery for stuff like this) but a couple of things definitely pop out at me with what you're doing here that may help you resolve the issue.
First of all, I think you can rework the way you set up a vote and thus the way you set up the form for the vote. In the stories controller, for the show action, I'd set up the vote right away:
#vote = Vote.new(:story_id => #story.id)
This lets you set up your form as so:
= form_for(#vote), :remote => true do |f|
= hidden_field f.story_id
= submit_tag "Vote"
This is both a cleaner way of doing things, in my opinion, but also may fix the general issue you are dealing with, because you are now passing data with the form (the hidden field) in your POST request. Rails will behave unexpectedly if you perform AJAX POST requests that do not actually submit data.
In other words, your original form is likely running as an AJAX POST request but it would have worked better as an AJAX GET request, since it is not actually submitting data, it is simply "hitting" an URL.
I am not sure if you found the answer to your problem yet, but I wanted to post for others that may be looking for an answer similar to yours.
The code:
<%= form_tag :url => new_story_vote_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
will result in /stories/:story_id/votes/new url with a :post request. It won't work because the new route is a :get method request. If you wanted to go to the new method, you'll need to tell the form to use the get http method.
<%= form_tag :url => new_story_vote_path(#story), :remote => true, :html => { :method => :get } do %>
<%= submit_tag 'shove it' %>
<% end %>
However, I think that you are wanting to route to the create method in your controller. I would do something like:
<%= form_tag :url => story_votes_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
This should route correctly to the create method in your VotesController.
How could one do switch in ruby on rails something like:
case controller "home"
do home
case controller "about"
do about
else
do home
I currently have this code:
<% case current_page(:controller) %>
<% when "forums" %>
<%= render :partial => 'shared/sidebar/sidebar_forums' %>
<% when "events" %>
<%= render :partial => 'shared/sidebar/sidebar_events' %>
<% else %>
<%= render :partial => 'shared/sidebar/sidebar_frontpage' %>
<% end %>
Quoting from http://rails.nuvvo.com/lesson/6371-action-controller-parameters:
The params hash will always contain the :controller and :action keys, but you should
use the methods controller_name and action_name instead to access these values. Any other parameters defined by the routing, such as :id will also be available.
So you should definitely be able to access it via params[:controller], and, if the controller_name method is in scope in a view, you should use that instead.
As for the switch syntax itself, you do need to do it like
case controller_name
when "home"
do_home
when "about"
do_about
else
do_default
end
You could do some hacking and get
case true
when controller "home"
do_home
when controller "about"
do_about
else
do_default
end
But why?
Whenever you had to do something like this, that means there is something not right with the application design. Not that I have never done that in the past but I dont do this now and it is being frowned upon.
Instead of doing what you are doing now, if you namespace your controllers appropriately according to their responsibilities, after all they are just classes and handle the requests coming from the users,etc., then you may not have to do this switch statement. For example, after namespacing them you may have different layouts made of different partials for your views which may not require you to do this switching in your controller/views hence keeping the code clean.