I am building a fairly simple recipe app to learn RoR, and I am attempting to allow a user to save a recipe by clicking a link rather than through a form, so I am connecting the user_recipe controllers 'create' function through a link_to.
Unfortunately, for some reason the link_to is calling the index function rather than the create.
I've written the link_to as
<%= "save this recipe", :action => 'create', :recipe_id => #recipe %>
this link is on the user_recipes/index.html.erb and is calling the 'create' function of the same controller. It doesn't seem to make a difference if I include the :controller or not.
The controllers look like this
def index
#recipe = params[:recipe_id]
#user_recipes = UserRecipes.all # change to find when more than one user in db
respond_to do |format|
format.html #index.html.erb
format.xml { render :xml => #recipes }
end
end
def create
#user_recipe = UserRecipe.new
#user_recipe.recipe_id = params[:recipe_id]
#user_recipe.user_id = current_user
respond_to do |format|
if #menu_recipe.save
format.html { redirect_to(r, :notice => 'Menu was successfully created.') }
format.xml { render :xml => #menu, :status => :created, :location => #menu }
else
format.html { render :action => "new" }
format.xml { render :xml => #menu.errors, :status => :unprocessable_entity }
end
end
In the standard REST scheme the index action and the create action both have the same url (/recipes) and only differ in that index is accessed using GET and create is accessed using POST. So link_to :action => :create will simply generate a link to /recipes which will cause the browser to perform a GET request for /recipes when clicked and thus invoke the index action.
To invoke the create action use link_to {:action => :create}, :method => :post, telling link_to explicitly that you want a post request, or use a form with a submit button rather than a link.
Assuming you have default resources set up in your routes file, i.e. something like this
resources :recipes
The following will generate a link that will create a recipe; i.e. will be routed to the create action.
<%= link_to "Create Recipe", recipes_path, :method => :post %>
For this to work, JS needs to be enabled in your browser.
The following will generate a link that will show all recipes; i.e. will be routed to the index action.
<%= link_to "All Recipes", recipes_path %>
This assumes the default which is a Get HTTP request.
Related
My app has a modal sign in form that I display using ajax:
<% if !current_user %>
<%= link_to "Sign in", signin_path, remote: true %>
<% end %>
routes.rb
get 'signin', to: 'static_pages#signin', as: 'signin'
static_pages_controller.rb
def signin
respond_to do |format|
format.html { render :action => 'signin.js.erb' }
format.js { render :action => 'signin.js.erb' }
end
end
signin.js.erb
$('#modalPlaceholder').html("<%= j render(partial: '/static_pages/signin') %>");
$('#modalPlaceholder').show();
This works well.
I would now like to intercept actions that require user sign in and display this modal. In my application controller I have:
application_controller.rb
def require_signin!
if current_user.nil?
render :action => '../static_pages/signin.js.erb'
end
end
helper_method :require_signin!
This works when the originating action is remote: :true and rails simply redirects it however when the originating action is a standard request the action is intercepted correctly by the application controller however the modal is displayed on screen in raw html and not loaded correctly.
You can check format type of request and render for it.
def require_signin!
if current_user.nil?
if request.format.html?
#html render file here
else
render :action => '../static_pages/signin.js.erb'
end
end
end
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 %>
<td>
<%=link_to image_tag(phone.image, :class => 'list_image'), :controller => 'phones_feature_controller', :action => 'index', :id => phone.id %>
</td>
I want to have an image link to another controller.
This link is in my index page and its controller is phone. I have another controller phones_feature. I want to have a link to phones_feature's index page
my phones_feature_controller :
def index
#phones=Phone.find(params[:id])
respond_to do |format|
format.html # index.html.erb
format.json { render json: #phones }
end
end
You are adding controller to your controller name.
<%=link_to image_tag(phone.image, :class => 'list_image'),:controller => 'phones_feature', :action => 'index', :id=>phone.id %>
check url_for documentation
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......
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' }