I've got a really simple rails question here but I can't seem to find the answer anywhere. I guess some of the problems stem from me following a tutorial for Rails 1.2 with Rails 2.1. Anyway..
I'm writing a blog system and I'm implementing the comments bit. I have comments displaying fine once I've created them using script/console, but getting the comment form itself working is the hard bit.
In posts_controller.rb I have
def comment
Post.find(params[:id]).comments.create(params[:comment])
flash[:notice] = "Added comment"
#render :action => show
redirect_to :action => show
end
and in show.html.erb (the view) I have
<%= form_tag :action => "comment", :id => #post %>
<%= text_area "comment", "body" %><br>
<%= submit_tag "Post Comment" %>
When I submit the form it tries to go to the urb /posts/comment/1 which is obviously incorrect, and it complains that it can't find a template. Obviously I don't want a template there because I've told it to redirect to the show action because I want it to just re-display the post's show page, with the new comment there.
I've tried both the commented out line (render :action => show) and the redirect_to line, and neither seem to do anything at all.
I'm sure I'm missing something simple, but what is it?
Does redirect_to :action => 'show', :id => params[:id] with quotes around show work?
Rails 2.1 embraces "RESTful resources". show just happens to be the name of one of the predefined REST actions that all rails controllers use.
Rails does some magic behind the scenes, and :show is equivalent to "display this one specific element with a specific given ID". Sounds like it's getting mixed up with that. The ID is probably defaulting to "1". Hence the generated URL you're seeing from the render call
The Rails 2.1 way of doing it would use the following actions and templates:
index - displays the full list of comments
create - add a new comment
show - display a specific comment only (not the full list). Doesn't sound like this is what you want, but the "magic" inside rails will default to this.
There are also actions for new (show view to enter a new comment) edit (show view to do an edit of an existing comment) update (handle update submission) and destroy (duh), but it doesn't look like you'd use them in this example.
Do you have a link to the tutorial? Wouldn't be too hard to port it to Rails 2.1 style.
yes, you use old rails style.
Something new:
form_for :comment, :url => { :post_id => #post } do |f|
f.text_area :body
submit_tag "Post"
end
you can use resources for posts and comments, search google for better tutorial or install rails 1.2.6:
gem install -v 1.2.6 rails
Related
UPDATE 3:
For anyone who reads this, this is why it wasn't working as expected in update 2 below: Passing a local variable to a partial that is rendered after the view has already loaded
If anyone knows how to solve that issue, let me know please.
UPDATE 2:
I updated the javascript with the quotation marks and it partially works...in the sense that the javascript is now functional and it will cause a string of text to appear on the page when I click the link as long as I have the partial only contain a string of text. However, when the partial includes the form fields code, something goes wrong.
If I just paste the following render code directly into the form in the new.html.erb view, it produces a new form section properly.
<%= render "add_round", f: f %>
However, when I try to include similar code in comps_helper.rb and then reference it from the link_to, it does not work:
In comps_helper.rb:
def addRound(f)
render "add_round", f: f
end
In new.html.erb:
<%= link_to "render it!", addRoundLink_path, remote: true %>
<div id="some_id"></div>
And I changed addRoundLink.js.erb to:
$("#some_id").html("<%=j addRound(f) %>"); #Is this the correct change to have made here?
Clicking the link_to link does nothing in that case.
Any thoughts?
UPDATED CODE:
Thanks for the reply. I've made the following changes and it still does not appear to be working. The link appears at the bottom of the form but when clicked does not change anything. What am I missing?
routes.rb:
resources :comps
match '/new_competition', :to => "comps#new"
get "/addRoundLink" => "comps#addRoundLink", :as => :addRoundLink
Note: I included the other 2 lines related to "comps" just in case those would cause an issue.
comps_controller.rb:
def addRoundLink
respond_to do |format|
format.js
end
end
comps_helper.rb:
def addRound
render "add_round"
end
addRoundLink.js.erb:
$("#some_id").html(<%=j addRound %>);
comps/new.html.erb:
<%= link_to "render it!", addRoundLink_path, remote: true %>
<div id="some_id"></div>
Thanks.
ORIGINAL QUESTION
First off, I'm new to rails. I've read and tried many solutions to similar questions but nothing has worked so far.
I created a form with rails form_for and fields_for. The form creates a new competition (comp). The competition has many rounds. The top half of the form (the form_for section) accepts the details about the competition as inputs and the bottom half of the form accepts details about each round (the fields_for section). The form works perfectly in this basic format.
I took all the code that is in the fields_for section and put it into a partial. My plan was to then create a "add new round" link to the bottom of the form that would simply display the partial above the link each time the link is pressed. This would add a new section to the form for a new round and allow the user to input as many rounds as they'd like. This is the part that I am struggling to make work.
I added this code to my comps_helper:
def addNewRound
render "add_round"
end
This renders the file /views/comps/_add_round.html.erb.
My question is: how do I get this to render in the form when a link is clicked. As far as I can get with the research I have done is:
<%= link_to "Add new round", { }, :remote => true %>
I don't exactly know what is supposed to go in the {} that will execute the addNewRound method. And I don't know what, if anything, I need to add to my comps_controller file.
Thanks so much for the help.
You have to create an action in your controller
app/controllers/some_controller.rb
def hello
respond_to do |format|
format.js
end
end
and define a route to this action.
routes.rb
get "/hello" => "some#hello", :as => :hello
then create a link to this action like that:
<%= link_to "render it!", hello_path, remote: true %>
<div id="some_id"></div>
When you click this link it will find its way to your action and respond with js(javascript) because we told action to respond with only js.
At the end render the partial to anywhere you want in your view(*in this example to the some_id div*)
app/views/some/hello.js.erb
$("#some_id").html("<%=j addNewRound %>");
WARNING: Creating dynamic forms is a pain. You will face a lot of problems (like setting different ids for new form elements etc...). I highly recommend you to use ryan bates nested_form gem
I am completely new to RoR. I have a parameter in one view of a controller now how can i get it in another view of the same controller?
You can set up a form or a link_to in form-a and make a HTTP (POST/GET) to form-b. Remember that you can put also any HTML (or JS) in your view that you like.
Have a look at:
link_to
link_to "Profile", :controller => "profiles", :action => "show", :id => #profile
# => Profile
If you want to link to a associated table you can easy do this with:
# #person.company.name is the name of the link
# company_path(#person.company) is the associated model
<%= link_to #person.company.name, company_path(#person.company) %>
I approve you to read the ruby on rails guides
Read the getting started chapter and then create the blog application you will see
that gives you a great entrace to ruby on rails.
Try to understand the Rails way.
I can't figure out how to upgrade this code from Rails 2 to Rails 3:
<% remote_form_for(item, :update => 'div_id') do |f| %>
...
I tried this:
<%= form_for :item, :remote => true, :url => { :controller => "items", :action => "create" }, :update => 'div_id' do |f| %>
...
It creates the new item but it fails in updating the content within <div id="div_id"></div> tags. It seems Rails 3 no longer supports the ":update" option for a remote form_for. Any suggestion?
You could use RJS, but that's being deprecated too (and for good reason). The simplified, best-practices way to handle this in Rails 3+ is as follows (assuming jQuery):
# your_view.html.erb
<div id="receiver-id"></div>
<%= form_for :some_model, :remote => true, :id => 'form-id' do |f| %>
...
<% end %>
# application.js (or any other .js loaded on the page)
$(function(){
$('#form-id').bind('ajax:success', function(xhr, data, status){
$('#receiver-id').html(data);
});
});
The ajax:success hook gets called by the jquery-ujs (aka jquery-rails, aka rails-ujs) remote link/form handler. See for yourself. There are lots of other callbacks/hooks available for you to use, too. If you wanted to make this even more flexible, you could use live instead of bind, and bind to a class that dictates where the ouput goes (e.g. "sidebar") and then all remote links/forms with the sidebar class would have their HTML response go to div#sidebar.
The most straightforward way to do this would be to write a javascript view template, e.g. create.js.erb which would look something like this:
$('#div_id').html("<%= escape_javascript(render(#item)) %>");
(depending on your setup, of course, I'm assuming an #item variable and an associated _item partial)
Edit:
coreyward is right. This is the RJS way which is more of the old fashioned Rails 2.x "Rails way". It's probably more familiar, but has issues. Your specific case is one of them, actually, as typically you might bind to an HTML element to update using the record's id (e.g. div #item_1), and in the create case there is no id available beforehand, complicating matters.
Binding via clientside JS eliminates this issue. RJS works in something of a vacuum, making assumptions about the state of the client's HTML and having no access to it.
I know the question is old but I when migrating to Rails 3 I found a pretty good way of doing this, so I thought I would post it here in case anyone else is in a similar solution.
In layouts/update_page.js.erb I put this file:
$j('#<%=#update_div_id||"list_div"%>').html('<%= escape_javascript render(:partial => (#partial_div||"index"), :locals => #local_hash) %>');
This is mainly used for searches that use remote, so in the index action in the controller, I just added the following code.
respond_to do |format|
format.html
format.js {render 'layouts/update_page'}
end
Since remote is being used, it will always try to use javascript first, so it will render the update_page.js.erb file from above. For us, we almost always use the div#list_div on our index pages, so we update that by the default, however if you need to update something different, you can pass in #update_div_id, and if you need to render a different page, you can pass in #partial_div.
To clarify, for a lot of things, it is probably better practice to use the callbacks, but I found this to be a much easier way, when we had to migrate over nearly 100 of these calls.
So, I have something of an odd controller/view setup, editing a Product model object occurs in the listings controller/view. There is a long-winded explanation for why this is, but I digress. However, when I submit the form, I get the error Couldn't find Product without an ID . What gives? Strangely, when I look at the params sent with the request, the ID attribute is assigned to the 'format' key. ?!.
The controller code is very simple. Edit Action:
def edit
#edit = Product.find(params[:id])
end
Update Action:
def update
#edit = Product.find(params[:id])
if #edit.save
redirect_to :url => listings_display_path
end
end
Here is my form_for code:
<% form_for #edit, :url => (listings_update_path(#edit)) do |f| %>
Edit, the trace:
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"st17LW0S9uENaV8UBcxKUfRH67oo+r3TuFAxiPKMCEc=",
"product"=>{"brand"=>"test_brand",
"productname"=>"test_product",
"category"=>"test_category",
"regprice"=>"4",
"saleprice"=>"2",
"description"=>"description"},
"commit"=>"Submit",
"format"=>"21"}
Edit: routes.rb
resources :product do
resources :promotions
collection do
get "replace"
end
end
#listings
match 'listings/index' => 'listings#index'
match 'listings/display' => 'listings#display'
match 'listings/edit' => 'listings#edit'
match 'listings/update' => 'listings#update'
Edit: create action
def create
#product = Product.new(params[:product])
#product.user = current_user
if #product.save
redirect_to :action => 'index'
end
end
First, for an alternate approach to editing multiple records on a single view, try this railscast: http://railscasts.com/episodes/198-edit-multiple-individually
Second, this is unconventional but your whole approach is unconventional...
You can stick a hidden field in the form with the ID in it. Something like:
<%= f.hidden_field, :product, :id %>
Then check your params hash and the id will be in there. You should be able to access it in the controller using something similar to:
# untested
#edit = Product.find(params[:product][:id])
Off the top of my head I'm not sure how it will be stored in your params hash but it will be there and you'll be able to access it like any other hash attribute.
Good luck!
--EDIT--
Also, regarding your comment about lack of flexibility in Rails -- one thing I've learned is that Rails isn't inflexible, but it is highly optimized for particular conventions. The developers refer to this as being "highly opinionated" software, which means:
It can do just about anything you care to do it any way you want to do it, but...
There's almost always a "preferred" way which is better, faster (harder stronger lol).
You would save yourself tons of time and energy -- and probably have a lot of fun -- grabbing the Beginning Rails 3 book. You could work through it in a weekend, and when you were done you would have a great primer on the "Rails Way" which would hopefully help you go from "I don't get why Rails doesn't do this or that" to "I get how Rails works and how easy it is to do what I want to do by following X pattern". That's what happened for me anyhow.
Again good luck!
Try this
<%= form_for #edit, :url => listings_path(#edit), :html => {:method => :put} do |f| %>
You need to fix the routes that are for a single product instance to have the id:
match 'listings/index' => 'listings#index'
match 'listings/:id/display' => 'listings#display'
match 'listings/:id/edit' => 'listings#edit'
match 'listings/:id/update' => 'listings#update'
I'm creating in my index page of my ruby on rails program, a list of the most commonly searched for terms in my database and hence each time a user selects a specific category this is written to another database.
What i would like it to create a hyperlink and pass a certain amount of parameters to a form like is usually done with a select_tag but instead with just a hyperlink, i would like to pass a set of hidden fields that i have on the page as well as what the user has selected.
To give you a better idea, basically i have the following structure in my program:
User inputs a search on (index.html.erb), user clicks on submit tag
action, user is taken to search.html.erb page and is displayed a set of refined categories + some fields, submit button,
user is taken to closest.html.erb (which uses parameters from the previous form by invoking the params[:searchSelected] and a few other params. )
I would also like to add this functionality:
Mimick this same operation, but instead of going in the search.html.erb, i would click on an already refined search category on the index.html.erb page (from a link_to , transmit as parameters which link_to the user has chosen + the hidden fields.
i Currently have this code
#stats.each do
|scr|%>
<%= link_to scr.category, :action => 'closest', :id => scr.category%>
I'm not sure if this is relevant, but i currently have the following routes in my routes.rb file
map.resources :stores, :collection => { :search => :get }
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
would anyone please assist me please? this is my first ruby on rails project and i would really like to find a way around this please
I am not sure if this is what you were thinking, but you can add additional parameters to the link_to tag. They are then available in your controller. So:
<%= link_to scr.category, :action => 'closest', :id => scr.category, :other_param => "test" %>
Will be available in your controller.
def closest
params[:other_param] == "test" #this will be true
end
i managed to resolve this by taking the params[:id] and then according to the value either set my own values (instead of the hidden ones in the index.erb which i had set manually anyway) and otherwise, continue as usual had i placed a regular search
View:
<%= link_to obj.ptc_devicename ,"/wiuconfig/hd?idval=#{obj.id.to_s}&val=#{#devicetype}",:value => obj.ptc_devicename,:id =>obj.id %><br/>
Controller:
#Heading= params[:val]
#id=params[:id]
value will be id is 2 and val is #devicetype