Rails linking to another controller in different view - ruby-on-rails

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.

Related

routes when nested resource and nested attribute

I have a Review model which is nested resource of Publication model. Review model have accept_nested_attributes_for review_comments. I wonder how could I show delete path to delete review_commment?
<% #review.review_comments.each do |review_comment| %>
<%= link_to "delete", ???, method: :delete %>
<% end %>
review.rb
has_many :review_comments, :dependent => :destroy
accepts_nested_attributes_for :review_comments, :allow_destroy => :true
review_comment.rb
belongs_to :review
publication.rb
has_many :reviews
routes.rb
resources :publications do
resources :reviews
end
resources :review_comments
UPDATE
def create
#review_comment = ReviewComment.new(params[:review_comment])
if #review_comment.save
redirect_to #review_comment, notice: 'Review comment was successfully created.'
....
end
def destroy
#review_comment = ReviewComment.find(params[:id])
#review_comment.destroy
redirect_to :back, notice: "Deleted"
end
UPDATE
review_comments GET /review_comments(.:format) review_comments#index
POST /review_comments(.:format) review_comments#create
new_review_comment GET /review_comments/new(.:format) review_comments#new
edit_review_comment GET /review_comments/:id/edit(.:format) review_comments#edit
review_comment GET /review_comments/:id(.:format) review_comments#show
PUT /review_comments/:id(.:format) review_comments#update
DELETE /review_comments/:id(.:format) review_comments#destroy
link_to with a method anything other than GET is actually a bad idea, as links can be right clicked and opened in a new tab/window, and because this just copies the url (and not the method) it will break for non-get links.
Also, links are clicked on by web page indexing spiders, and even though the links in question are probably only available to logged in users (and therefore not spiders) it's still bad practise.
It's better to use button_to instead, which makes rails generate a mini-form to produce the same result.
From a practical point of view buttons are better (for the above reasons) but they're also better from a conceptual point of view: generally speaking, links should "take you somewhere", whereas buttons should "do something". It's better to keep these two basic functionalities seperate.
Something like this,
button_to t('general.delete'), :review_comment_path(review_comment), :method => :delete, :confirm => t('review_comment.confirm_delete'), :title => t('review_comment.delete_question')
For your routes:
<%= link_to "delete", review_comment, method: :delete %>
class ReviewCommentsController < ApplicationController
def destroy
#review_comment = ReviewComment.find(params[:id])
#review_comment.destroy
redirect_to review_comments_path # Or another path
end
end

Delete action and destroy method

I have something like this in view:
<% if actions.include? "delete" %>
<%= link_to 'UsuĊ„', asset_path(asset), :method => :delete, :data => { :confirm => "Want to delete it?" }, :role => "link" %>
<% end %>
and this in assetcontroller:
def destroy
#asset = current_user.assets.find(params[:id])
#asset.destroy
redirect_to assets_path
end
the question is, why it "use" destroy method when action in view is "delete" ?
delete is method of HTTP protocol. destroy is the action of your controller.
Route with delete HTTP method leads to destroy action.
To edit this routes and make delete HTTP method lead to delete action (for example), you should edit config/routes.rb file.
This is because in your routes.rb file you have defined the model as a resource (or a generator like scaffold did). This means that the default CRUD routes are generated. If you want to do it another way, use your own routes instead of generating them.
http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions

How to make a custom route in Rails? By custom I mean one that reacts to params

So essentially I've setup a route to match "products/:product", which seems to respond to a page like baseurl/products/toaster and displays the toaster product. My problem is I can't seem to use link_to to generate this path, and by that I mean I don't know how. Any help on this?
There are several solutions on this one :
<%= link_to 'Toaster', { :controller => 'products', :action => 'whatever', :product => 'toaster' } %>
But it's not really Rails Way, for that you need to add :as => :product at the end of your route. This will create the product_path helper that can be used this way :
<%= link_to 'Toaster', product_path(:product => 'toaster') %>
Within your routes file you can do something like:
match "products/:product" => "products#show", :as => :product
Where the controller is ProductsController and the view is show
within the Products controller your have
def show
#product = Hub.find_by_name(params[:product])
respond_to do |format|
format.html # show.html.erb
end
end
Where whatever is in the products/:product section will be available via params.
Then, since we used :as in your routes you can do this with link_to:
<%= link_to product(#product) %>
Where #product is an instance of a product or a string. This is just an example and the param can be anything you want, the same goes for controller/action. For more info you should check out this.
Hope this helps!

Rails 3: Single Model backing multiple Controllers

Ok, I have search Google, API's as well as StackOverflow and have found no real decisive help for my issue. So here goes!
I have a Polymorphic model setup named Favorite and it ties to the User. Being that Favorite is Polymorphic I of course can use the relationship to allow my user to add pretty much any entity in my application as their Favorite.
Each of these Favorite relationships between the user and a specific model I want to be able to call different things such as 'Favorite' or 'Like' or 'Friends'. This allows me to have a different Controller with Views to manage each of these different relationships so they are more understandable to the user and myself. Hence I am covering the global generic idea of Favorites with a more precise idea of a 'Friend'.
So I went ahead and created a Friend controller with its associated views to handle the Favorite relationship between a user and other user's in the system.
But what I have found is that Rails expects me to pass a 'Friend' model in all of my interactions between views and controller even though I want to use the Favorite model and I get 'uninitialized constant Friend' as an error in my view. How do I get past this 'convention', how do I make the controller and views if necessary understand that I am using the Favorite model as my underlying model not the Friend?
I considered creating a new model named 'Friend' and inheriting it from 'Favorite' just to fool the controller, but man that just seems like a waste of energy to me. Any ideas out there?
CODE EXAMPLE this is using the Favorite polymorphic model to ButtSlap another User. Each form partial is pass the User as a local variable called local_entity.
ButtSlapController
class ButtSlapsController < AuthorizedResourceController
def create
#favorite = current_user.favorites.build(params[:favorite])
respond_to do |format|
if #favorite.save
flash[:success] = 'butt slap successful!'
format.html { redirect_to('/lounge') }
# format.js { render :action => "create_success"}
else
flash[:success] = 'ah poop!'
format.html { redirect_to('/lounge') }
# format.js { render :action => "create_failure"}
end
end
end
def destroy
#favorite = current_user.favorites.find(params[:id])
respond_to do |format|
if #favorite.destroy
flash[:success] = 'butt slap has been successfully removed.'
format.html { redirect_to('/lounge') }
# format.js { render :action => "create_success"}
else
flash[:success] = 'ah poop!'
format.html { redirect_to('/lounge') }
# format.js { render :action => "create_failure"}
end
end
end
end
Creates The ButtSlap
<%= form_for current_user.favorites.build, :as => :favorite, :url => butt_slaps_path do |f| %>
<div><%= f.hidden_field :favorable_id, :value => local_entity.id %></div>
<div><%= f.hidden_field :favorable_type, :value => local_entity.class.to_s %></div>
<div class="actions"><%= f.submit "butt slap!" %></div>
<% end %>
Removes the ButtSlap
<%= form_for current_user.get_favorites(
{:id => local_entity.id,
:type => local_entity.class.to_s}),
:html => { :method => :delete }, :url => butt_slaps_path do |f| %>
<div class="actions"><%= f.submit "take back" %></div>
<% end %>
Well it all turned out to be a little gem called CanCan v1.6.4
I have been using CanCan for Authorization within my application and when declaring your authorization rules in your Ability class you can either do it by Model or by Controller or a mixture.
In order to handle this I setup 2 root Controllers which inherited from ApplicationController. The first 'AuthorizedController' is used for all controllers which do not use a Model and the second 'AuthorizedResourceController' is used for all controllers which are backed by a Model.
Turns out that for my ButtSlap controller I had it setup as an AuthorizedResourceController and by doing so CanCan was automatically looking to pull and authorize either a collection or a single model based off of the controller's name 'ButtSlap'. But due to the fact that I was using the Favorite model on the backend every time I tried to post to the controller CanCan tried to load its imaginary model based off of its convention. And I thus received the errors messages 'Uninitialized Constant 'ModelName''.
Once I switched the ButtSlapController from an AuthorizedResourceController over to a AuthorizedController CanCan no longer looked to instantiate and authorize a model based off the controller name and it moved to controller based authorization instead and just like everyone was saying 'Poof' my confusion as to why Rails was looking for a Model tied to a controller name was gone.
You really have to love bugs like this, they really stretch your limits as well as your keyboard stockpile (I tend to throw keyboards when I get frustrated ;)

Managing restful resources in Rails 3

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

Resources