Simple one model singular resource routing problem - ruby-on-rails

I have a stripped down shopping cart application, currently with one model "cart", the cart id is stored in a session.
the cart controller has this method so we always have a cart
def initialize_cart
if session[:cart_id]
#cart = Cart.find(session[:cart_id])
else
#cart = Cart.create
session[:cart_id] = #cart.id
end
end
my routes file has this one line
map.resource :cart
my cart/show view looks like this, i have added a form to it so that ultimately i can update the quantity of items, but for now i am just editing the created_at attribute.
<% form_for(#cart) do |f| %>
<%= f.date_select :created_at %>
<p>
<%= f.submit 'Update' %>
</p>
<% end %>
<%= link_to 'Edit', edit_cart_path(#cart) %> |
<%= link_to 'Back', cart_path %>
and finally, my update action looks like this:
def update
##cart = Cart.find(params[:id])
respond_to do |format|
if #cart.update_attributes(params[:cart])
format.html { redirect_to(cart_path) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #cart.errors, :status => :unprocessable_entity }
end
end
end
when i make a change to "created_at" attribute on the "show" page, the attribute is successfully updated, but when i get redirected, i get a bizare url like this
http://192.168.0.10:3000/cart.%23%3Ccart:0x23d46fc%3E
I have fiddled with the update action, and can get the whole thing to work perfectly by doing this
# PUT /carts/1
# PUT /carts/1.xml
def update
##cart = Cart.find(params[:id])
#respond_to do |format|
if #cart.update_attributes(params[:cart])
redirect_to(cart_path)
# head :ok
#else
# render :action => "edit"
# render :xml => #cart.errors, :status => :unprocessable_entity }
end
#end
Its something to do with the respond_to block that is causing it to mess up, i would really appreciate any help i can get with this.
Thanks

For singular resource, you don't need to specify the object in the routes.
So you should use this:
<%= link_to 'Edit', edit_cart_path %>
===== UPDATED =====
I just found your real problem ^^" (but the original should be true too)
You used form_for(#cart) do |f|, which produced that ugly path
Please change to form_for(#cart, :url => cart_path) do |f|
I don't know why too, but it should be ok......

Related

Button call controller method, display results

I have resources
User #from devise
Stream
Subscription
In my routes.rb file I have subscriptions as a nested resource to users.
resources :users do
resources :subscriptions
end
In Stream#show view I have a button that should save the #stream.title to #subscription.title.
<%= button_to "Subscribe", subscriptions_path(#subscription), :class => "button", :method => :post , :remote=>true %>
In my Subscriptions Controller
def create
#stream = Stream.friendly.find(params[:stream_id])
#subscription = current_user.subscriptions.create(subscription_params)
#subscription.title = #stream.title
#subscription.save
respond_to do |format|
if #subscription.save
format.html { redirect_to #subscription, notice: 'Subscription was successfully created.' }
format.json { render :show, status: :created, location: #subscription }
else
format.html { render :new }
format.json { render json: #subscription.errors, status: :unprocessable_entity }
end
end
end
Rake route
POST /users/:user_id/subscriptions(.:format) subscriptions#create
And in my Stream#index view I want to display the #subscription.title ' s
<tbody>
<% for subscription in #subscriptions %>
<tr>
<td><%= subscription.title %></td>
</tr>
<% end %>
And in my Streams Controller
def index
#streams = Stream.search(params)
#subscriptions = current_user.subscriptions.build(subscription_params)
end
I have added a reference index for each subscription to a user
class AddIndexes < ActiveRecord::Migration
def change
add_reference :subscriptions, :user, index: true
end
end
I am recieving a NoMethodError in Streams#show, undefined method 'subscriptions_path'.
And a NameError in StreamsController#index, undefined local variable or method 'subscription_params'
You get undefined method subscriptions_path because rails translates your format.html { redirect_to #subscription, notice: 'Subscription was successfully created.' } wrong. Change your #subscription into a proper helper path call. If you're not sure what you should provide here, you may want to run rake routes > routes.txt in the shell and find your subscriptions route definition there and call it with _path
You get undefined method subscription_params because most probably you haven't defined subscription_params anywhere. You most prolly want to access your subscription params like params[:subscription]. As for the proper key when it comes to accessing the params hash, it all depends how you build your form in a view.
<%= button_to "Subscribe", subscriptions_path(#subscription), :class => "button", :method => :post , :remote=>true %>
The resource above doesnt exists, you have only defined a nested resource subscriptions inside users.
So you should have something like this instead, using the nested resource user_subscriptions_path.
<%= button_to "Subscribe", user_subscriptions_path(#subscription), :class => "button", :method => :post , :remote=>true %>

Setting rails routes to url path

I'm new to rails and having problems with my routes. When a link gets submitted, it should go to 'http://example.com' although it now goes to localhost:3000/links/www.example.com
I am running ruby 3.2.8 and ruby1.9.3p194. Not sure how much info is needed. Here's where it's at.
In my view I have:
<p>
<h1><%= #link.title %></h1>
<%= link_to #link.url, #link.url %><br />
<p>Posted by: <% #link.user %> at <%= #link.created_at %></p>
</p>
My controller is set as:
class LinksController < ApplicationController
def show
#link = Link.find(params[:id])
end
before_filter :authenticate_user!
def new
#link = Link.new
end
def create
#link = Link.new(params[:link])
respond_to do |format|
if #link.save
format.html { redirect_to #link, notice: 'Link was successfully created.' }
format.json { render :json => #link, status: :created, location: #link }
else
format.html { render :action => "new" }
format.json { render :json => #link.errors, :status => :unprocessable_entity }
end
end
end
end
In my development.rb file I have:
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
And my routes are:
resources :pages
resources :links
root :to => "pages#index"
After countless searches, I've had no luck since I am a beginner. Any suggestions for how to reset the link paths greatly appreciated.
There is nothing to do with routes or Rails here.
You need to output http:// in front of your links, if you want to link off-site. Either enter in in the textbox when you submit your link, or modify your code to conditionally prepend it:
<% link_href = #link.url %>
<% link_href = "http://#{link_href}" unless link_href.match(/^https?:\/\//) %>
<%= link_to #link.url, link_href %><br />

Why can't I build more than one nested attribute here?

this is my form code:
<%= simple_form_for setup_video(#video) do |f| %>
<% f.fields_for :comment_titles do |t| %>
<%= t.input :title, :label => "Comment Title:" %>
<%= t.button :submit, :value => 'Add', :id => 'add_comment_title' %>
<div class='hint'>Let your listeners know what comments you want by adding a guiding title for them. Pose a question, ask for feedback, or anything else!</div>
<% end %>
<% end %>
I have has_many :comment_titles and accepts_nested_attributes_for :comment_titles, :comments in my model. when I create a new comment_title in the form, the old one is replaced. I want an additional one to be built. How can I do this?
Here are the video controller actions:
def new
#video = Video.new
respond_to do |format|
format.js do
render_to_facebox(:partial => 'add_video')
end
end
end
def create
#video = current_user.videos.new(params[:video])
respond_to do |format|
if #video.save
format.html { redirect_to(#video) }
else
format.html { render :action => "new" }
end
end
end
I think this is actually what is needed:
def update
#video = current_user.videos.find(params[:id])
respond_to do |format|
if #video.update_attributes(params[:video])
format.html { redirect_to(#video) }
format.js
else
format.html { render :action => "edit" }
end
end
end
The edit action here will provide a form which will allow you to edit the existing record as well as its nested attributes. This is why it's replacing the existing object.
If you only want people to add new comment titles then I would recommend building a new object in your edit action like this:
def edit
video = current_user.videos.find(params[:id])
video.comment_titles.build
end
Then this will be available as an additional row in your fields_for call. To only make this show new objects:
<% f.fields_for :comment_titles do |t| %>
<% if t.object.new_record? %>
# stuff goes here
<% end %>
<% end %>
However this restricts people to being able to only add new items in an edit action, which may seen counter-intuitive to some users.

Rails does not display error messages on a form in a custom method

I've created a custom method called checkout in my app. I create an order (which is done my adding products to my "cart"), assign it to my client, and then I head to my checkout screen where I confirm the items and enter their customer order number and complete the order (submit).
Everything works great except that it doesn't display error messages. I'm able to display a flash error notice (seen in complete_order method) when things go wrong but it doesn't specify the details like a normal form would. The error messages should appear if the customer order number is not unique for that client.
Below is the custom method (checkout) related code.
Order Model:
validates_uniqueness_of :customer_order_number, :scope => :client_id
Orders_controller:
def checkout
#order = current_order
end
def complete_order
#order = current_order
respond_to do |format|
if #order.update_attributes(params[:order])
#order.complete #sets submitted datetime and state to 'complete'
flash[:notice] = 'Thank you! Your order is being processed.'
format.html { redirect_to( products_path ) }
format.xml { head :ok }
else
flash[:error] = 'Please review your items' #added to confirm an error is present
format.html { redirect_to( checkout_path ) }
format.xml { render :xml => #order.errors, :status => :unprocessable_entity }
end
end
end
And the form in the checkout view:
<% form_for #order, :url => { :controller => "orders", :action => "complete_order" } do |f| %>
<%= f.error_messages %>
<%= f.text_field :customer_order_number, :label => "Purchase Order Number" %>
<p>
<%= f.submit 'Complete Order', :confirm => 'Are you sure?' %> <small> or <%= link_to 'cancel', current_cart_path %></small>
</p>
<% end %>
Any idea how I can display the specific error messages?
Change redirect_to to render in else condition otherwise checkout method get called again & no error will displayed.
else
format.html { render :action => 'checkout' }

Adding my comments to the index view...Ruby on Rails

Ok...I am new to rails so this may be a stupid question but need help. I just watched and implemented Ryan Bates screencaset about setting up a blog. You can see it here http://media.rubyonrails.org/video/rails_blog_2.mov. Here is the skinny:
Two tables: Posts and Comments. Everything works great including the addition of comments via AJAX. The default development of this blog gives you the index.html.erb view where you can view all the posts
def index
#posts = Post.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #posts }
format.json { render :json => #posts }
format.atom
end
end
The comments are only viewed via the show.html.erb page and is displayed via this code in that file:
<%= render :partial => #post %>
<p>
<%= link_to 'Edit', edit_post_path(#post) %> |
<%= link_to 'Destroy', #post, :method => :delete, :confirm => "Are You Sure" %> |
<%= link_to 'See All Posts', posts_path %>
</p>
<h2>Comments</h2>
<div id="comments">
<%= render :partial => #post.comments %>
</div>
<% remote_form_for [#post, Comment.new] do |f| %>
<p>
<%= f.label :body, "New Comment" %><br/>
<%= f.text_area :body %>
</p>
<p><%= f.submit "Add Comment"%></p>
<% end %>
What I am trying to do is to get similair representation of the comments functionality to exist in the index.html.erb view (which I will hide with javascript). Which currently just looks like this:
<h1>Listing posts</h1>
<%= render :partial => #posts %>
<%= link_to 'New post', new_post_path %>
My initial thought was just to put this exact same code that is in the show.html.erb file in the index.html.erb file but that doesn't work. I have tried a bunch of things here but I am not familiar enough with Rails (or coding for that matter) yet to do this in a timely manner. I get two main errors. Either that I passed a nil.comments error or an undefined object/method (can't remember).
My question is what do I need to included in the post_controller, the comments_controller and the index.html.erb file to accomplish this. To be complete I have included the code in each below.
POSTS_CONTROLLER
class PostsController < ApplicationController
before_filter :authenticate, :except => [:index, :show]
# GET /posts
# GET /posts.xml
def index
#posts = Post.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #posts }
format.json { render :json => #posts }
format.atom
end
end
# GET /posts/1
# GET /posts/1.xml
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
# GET /posts/new
# GET /posts/new.xml
def new
#post = Post.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #post }
end
end
# GET /posts/1/edit
def edit
#post = Post.find(params[:id])
end
# POST /posts
# POST /posts.xml
def create
#post = Post.new(params[:post])
respond_to do |format|
if #post.save
flash[:notice] = 'Post was successfully created.'
format.html { redirect_to(#post) }
format.xml { render :xml => #post, :status => :created, :location => #post }
else
format.html { render :action => "new" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
# PUT /posts/1
# PUT /posts/1.xml
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
flash[:notice] = 'Post was successfully updated.'
format.html { redirect_to(#post) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.xml
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to(posts_url) }
format.xml { head :ok }
end
end
private
def authenticate
authenticate_or_request_with_http_basic do |name, password|
name == "admin" && password == "secret"
end
end
end
COMMENTS_CONTROLLER
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create!(params[:comment])
respond_to do |format|
format.html { redirect_to #post}
format.js
end
end
end
INDEX.HTML.ERB
<h1>Listing posts</h1>
<%= render :partial => #posts %>
<%= link_to 'New post', new_post_path %>
Here's one simple solution. Step 1, edit your index action to include all the comments belonging to each post.
def index
#posts = Post.all(:include => :comments)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #posts }
format.json { render :json => #posts }
format.atom
end
end
Step 2, edit your index view to display each post, followed by its comments:
<h1>Listing posts</h1>
<% #posts.each do |post| %>
<%= render :partial => post %>
<%= render :partial => post.comments %>
<% end %>
<%= link_to 'New post', new_post_path %>
Edit: I'm not 100% sure of the best way to include the comment creation form also. What I'd try first is this (in index.html.erb):
Try changing your index view to:
<h1>Listing posts</h1>
<% #posts.each do |post| %>
<%= render :partial => post %>
<%= render :partial => post.comments %>
<% remote_form_for [post, Comment.new] do |f| %>
<p>
<%= f.label :body, "New Comment" %><br/>
<%= f.text_area :body %>
</p>
<p><%= f.submit "Add Comment"%></p>
<% end %>
<% end %>
<%= link_to 'New post', new_post_path %>
This should render the "New comment" form for a given post under the comments for that post, but I'm not sure (without actually trying it out) whether the form submission AJAX will successfully update and refresh the index page.

Resources