I am trying to convert my Rails 2 app to Rails 3, but I can't delete any resources using my old Rails 2 code. To be precise I am trying to delete a resource, using this link:
<%= link_to image_tag("misc/delete.png"), #book, :confirm => 'Are you sure?', :method => :delete %>
And yet it doesn't work at all! It just behaves as if the :confirm option and :method option haven't been set at all, i.e. redirects me to the url of the #book object without even showing an alert box.
The generated HTML in Rails 3 is:
<img alt="Delete" src="/images/misc/delete.png?1205252772">
The generated HTML in Rails 2 was:
<img alt="Delete" src="/images/misc/delete.png?1279402305">
It's an obvious difference, but I've got no idea how I should handle this problem.
My controller looks like so:
class BooksController < ApplicationController
before_filter :require_admin, :only => ['new', 'create', 'edit', 'update', 'destroy']
# ....
def destroy
puts "-------------- DESTROYING BOOK --------------"
#book = Book.find(params[:id])
#book.destroy
flash[:notice] = "Successfully destroyed book."
session[:restore] = request.referer
redirect_to back(edit_author_url(#book.author))
end
end
And the string "destroying book" doesn't show on the console, so I think there surely must be something wrong.
Has something in the restful handling been changed in Rails 3 that I should get to know of?
Thanks, guys!
You need add the rails javascript library.
To jQuery : http://github.com/rails/jquery-ujs
To Prototype : http://github.com/rails/prototype-ujs
Related
I'm trying to enable the user to edit the number of credit cards they have on file, they'll have the option to delete it.
It would be simple enough in traditional rails, but I'm new to spree and not sure how things work during checkout.
In views:
- #cards.each do |card|
= card.last_digits
= "#{card.month+'/'+card.year}"
= button_to "delete", {:controller => :credit_cards,
:action => 'destroy', :id => card.id, :method => :delete, :confirm => 'are you sure?'}
Controller:
module Spree
class CreditCardsController < Spree::BaseController
def destroy
#credit_card = Spree::CreditCard.find(params["id"])
#credit_card.destroy
.
.
.
Right now the button generated seems to work, when I press on it from checkout/payment it goes to checkout/update/payment and then stops at checkout/confirm but the credit card in not deleted.
Any help would be greatly appreciated!
what's the filename of your controller? are you intending to override the spree class CreditCardsController? if so:
Spree::CreditCardsController.class_eval do
def destroy
#credit_card = Spree::CreditCard.find(params["id"])
#credit_card.destroy
...
end
end
...but i think that controller method is in the Api namespace. what about calling the drop_payment_source method? https://github.com/spree/spree/blob/45cec5215763da26e0089415f4c49afffd683bd9/core/app/models/concerns/spree/user_payment_source.rb#L13
...if you want define your own CreditCardsController class then you should setup something in your routes.rb file so you can use a route helper method in the button_to method (instead of calling out the controller & method name). also, you need to redirect or something in your destroy method. maybe to checkout_path? run rake routes to find more.
I this view is currently in the views/projects/show.html.erb file however I want it to use the website controller for deleting this file:
<%= link_to 'Delete', #website, :controller => 'website', :action => 'delete', method: :delete, data: {confirm: "Are you sure you want to delete this asset?"}%>
It returns the error 'Could not find action destroy in the ProjectsController'. Also i don't have #website defined in the projects controller so should I be using something else? Or am I still able to access it because it is defined in the websites controller.
#controllers/websites_controller.rb
class WebsitesController < ApplicationController
def new
#project = Project.find(params[:project_id])
#website = #project.assets.build(:type => 'Website', :project_id => Project.find(params[:project_id]), :asset_number => #project.assets.size + 1)
end
def create
#website = current_user.assets.build(website_params)
#website.update_attributes(:project_id => #project)
if #website.save
flash[:notice] = "Asset successfully added."
redirect_to(:controller => 'projects', :action => 'show', :id => #website.project_id)
else
render(:action => 'new')
end
end
def delete
#website = Asset.find(params[:id])
end
def destroy
asset = Asset.find(params[:id]).destroy
flash[:notice] = "The asset '#{asset.title}' has been destroyed Successfully."
redirect_to(:controller => 'projects', :action => 'index')
end
private
def website_params
params.require(:website).permit(:id, :project_id, :asset_number, :title, :type, :url, :page_rank, :rev_company ,:social_pages)
end
end
If you are using this link on the show page for projects then #website will not be available unless it is defined in the projects controller.
That said, if there is some relationship between the project and the website, you could use that as opposed to defining #website in your projects controller.
Also, as far as your link_to is concerned, I do not believe that you can specify controller and action in the link_to like that. Instead, you should use the path to #website. Which should make your link_to look something more like this:
<%= link_to "Delete", website_path(#website), method: :delete, data: {confirm: "Are you sure you want to delete this asset?" %>
However, the model that your websites_controller appears to handle is actually an Asset. Without seeing your routes it is hard to guess how you have set them up, but assuming that you do something like
map.resources :assets, :controller => 'websites'
in your routes. Then in your link_to instead of using website_path(#website) you would likely use asset_path(#website).
Generally speaking, it is rarely a good idea to defy rails convention by naming things inconsistently from your model in ruby. If your Asset model uses single table inheritance or you are implying something like single table inheritance and are using controllers to separate responsibilities, then this may perhaps be an exception, but you will still need to be careful to ensure you are mapping to the correct place in your routes.
You may want to read up on the rails guide for routing, as it is a very good resource and explains pretty well how destroy gets mapped, which in turn explains why the link_to for it looks the way that it does.
#website available in the show action is the the one defined in the projects controller because it is he one rendering the current html page.
Therefore the one you wish to delete is not available at the moment.
I'm testing a rails controller and attempting to perform a get with the code:
delete :remove_logs, :id => 3
And it consistently returns me an ActionView::MissingTemplate exception. I know that this is because there is no view associated with the get. There is a route for this method (from rake routes):
remove_logs /devices/remove_logs/:id(.:format) {:controller=>"devices", :action=>"remove_logs"}
The function itself works perfectly for the actually webpage as it's being called with:
<%= link_to "Remove History", remove_logs_path(device),
:class => "medium red button", :confirm => 'This will remove all history from
this device. Are you sure?', :method => :delete %>
So my question is, is there a way to bypass or trick the test to not attempt to access the view and just access the controller method? This isn't my system I'm testing so I really don't want to make a new blank view or anything similar.
I think the problem may be related with the code in controller (remove_logs action) which usually has some code about redirecting to another url like bellow:
def destroy
#tag = Tag.find(params[:id])
#tag.destroy
redirect_to :action => :index
end
I test with Test::Unit in my rails app, and it goes fine when having redirecting code.
I'm trying to implement the "Friendship" in my Rails 3 app as described in Railscast 163:Self Referential Assosication
I have everything set up as described. I am using a basic user model that logis in with Authlogic which works fine. However when I try to add a friend using the following link:
<% for user in #users %>
<%=h user.username %>
<%= link_to "Add Friend", friendships_path(:friend_id => user), :method => :post %>
<% end %>
I get a redirect to http://localhost:3000/friendships?friend_id=2 and a Unknown action The action 'index' could not be found for FriendshipsController error with no further explanation. This is expecially strange since I have a hard coded redirect back to the "User#show" method for my current user (i.e. redirect back to profile after adding friend).
If it helps, here is my "friendships#create" method:
def create
#friendship = current_user.friendships.build(:friend_id => params[:friend_id])
if #friendship.save
flash[:notice] = "Added friend."
redirect_to :controller => 'users', :action => 'show', :id =>'current_user'
else
flash[:notice] = "Unable to add friend."
redirect_to :controller => 'users', :action => 'show', :id =>'current_user'
end
end
Any idea what could be causing this? I found someone having a similar problem here but I couldn't find a definite fix: Rails 3 and Friendship Models
Thanks in advance for your help!
~Dan
I think that link_to put the arguments into the query string as it is creating with html link even if you put :method => :post if js is disabled.
you could simulte a post with javascript :onclik event.
aniway , use a link_to with method :post is generaly a bad idea.
in rails you could use button_to helper for this pourpose and style it like a link.
edit:
In Rails3 doc seems that link_to have to simulate the same behaviur of button_to when called with params :method=>:post
(dynamically create an HTML form and
immediately submit the form ).
but it's not true for me in Rails 3.0.3 even if javascript is enabled.
I will investigate.
anyway you should be using buttons and forms for anything that isn't a GET; hyperlinks intentionally don't allow for methods other than GET
edit2:
ok,
rails3 don't create a inline form for simulate the post request via link. in Rails3 a data-method=post attribute is added to the tag for manipulate it via javascript function. this way the request gracefully degradate in a get call if js is disabled.
It's a late answer but it's a solution to this problem (at least it works for me):
<%= link_to "Add Friend", {:controller => :friendships, :action => :create, :friend_id => user_id }, :method => :post %>
I know it's long overdue for your problem, but it may help someone :)
I have a name route:
map.up_vote 'up_vote', :controller => 'rep', :action => 'up_vote
But up_vote requires two arguments to be passed in, postID and posterID and I can't seem to figure how to do that in a partial, but in an integration test I have no issues.
Partial:
link_to 'Up Vote', up_vote_path, {:postID => session[:user_post_id], :postersID => session[:poster_id]}
Integration test:
post up_vote_path,{:postID => #latest.id,:postersID => users(:bob).id} (this works ok)
1) What is going on the in the partial?
2) What changes can I make to my tests to catch this?
A question: why are you passing your session variables in a link? You can get them directly from the session...
I don't know if there are any special reasons to put :user_post_id and :poster_id in the session but I recommend you two things:
1) Pass your variables in urls, sessions can be evil (try hitting back, refresh and forward on your browser)
2) Use resources in your URLs / controller actions logic.
Example (valid only if I got it right and you're voting an user's post):
routes:
map.resources :users do |user|
user.resources :posts do |post|
post.resource :vote
end
end
So you can have this url:
/users/:id/posts/:post_id/vote
And the link path:
link_to "Up", user_post_vote_path(#user, #post), :method => :create
I putting #user and #post instead of the integers because path methods accept them and you can build a shorter version with:
link_to "Up", [#user, #post, :vote] # or [:vote, #post, #user]
Implementing:
class VoteController ....
def create
# do your stuff here
end
end
This way it will be easier and RESTful.
Ryan Bates got a great episode on resources, it definately worths a look.
You want to pass your params in the ..._path
link_to "Up Vote", up_vote_path(:postID => session[:user_post_id], :postersID => session[:poster_id])
The integration test is written out differently than the link_to since your testing the act.
post "to" up_vote_path, "with these" {params}
Also since your doing a POST, you will want to add the appropriate :method option to the link_to