link_to one page but controller from another in Rails - ruby-on-rails

I've seen some similar questions on stack but I don't think this is a duplicate as each answer I've gottent has been specific to one underlying problem.
Ill keep it simple. I'd like to know how to click a link, have it take the user to one page but execute a def from another. This is in a rails application of a web crawler and Its something I thought would be quite simple but turned nasty on me.
At the moment I have:
<td><%= link_to 'Crawl!', crawl_path :controller => :crawl, :action => :crawl %>
This takes the user to the crawler's index page after its done running.
What I would like to do is redirect them to a different page. Namely jobs_path which shows a list of the crawlers sites and status (this is working fine, I just want to included it for relevance). If I try it like this:
<td><%= link_to 'Crawl!', jobs_path, :controller => :crawl, :action => :crawl %>
The user is directed to the jobs page but the crawler script never ran and thus the jobs list was never update. For the record, each job is just a url and the depth that it lies at.
Is this just a syntactical error or am I miles off the mark?
Any help appreciated.

What have you set your redirect_to in crawl#crawl as? Perhaps set it to redirect to jobs_path upon completion?

Related

How to create a href tag with link_to and action 'create'

I want to create a href tag like href=contacts/create. In my contacts_controller, I have a create GET action. I know this is against rails convention. I still need to create the above link using options = {controller=> 'contacts', action=>'create'}. It works for any other arbitrary action name
You can the hardcoded path option:
<%= link_to "Create", "contacts/create" %>
or the Rails generated path option:
<%= link_to "Create", { controller: "contacts", action: "create" } %>
This is not just against Rails' convention, but against sounds HTTP usage. This often causes serious problems that you can't predict in advance. Web crawling is just one of them, where something like the Google bot accidentally creates a new contact in your database, simply by crawling the page. Or script kiddies who find you have a create link, and send 100,000 clicks to it in quick succession.
Numerous other issues happen like this, including, at one well-known time, Google Chrome pre-fetching GET urls from the page to "speed up the user experience"; this was felt far and wide by sites that had used this technique. It's not an idle warning or a style issue: this can have a disastrous impact on your site.
First off this is really bad idea since GET requests should be idempotent. You're not just flouting convention - you're setting yourself and your users up for a really bad time since for example pressing the back and forward buttons will cause resources to be created - over and over. And there is guaranteed a better way to solve whatever you are trying to do such as:
# a "discrete form"
<%= button_to "Create contact", contacts_path, method: :post %>
# or use the rails ujs
<%= link_to "Create contact", contacts_path, method: :post %>
If you ABSOLUTELY have do this:
Rails.application.routes.draw do
get "contacts/create"
end
You can now do:
<%= link_to "Create", { controller: 'contacts', action: 'create' } %>
Congratulations, you broke the internets.
Like you mentioned, this is against rails convention, but if absolutely necessary, you can do this from your controller:
options = {controller=> 'contacts', action=>'create'}
view_context.link_to url_for(options)
If you need the href to only be the path, you can do:
options = {controller=> 'contacts', action=>'create'}
view_context.link_to url_for(options.merge(only_path: true))

create edit URL route that doesn't show :id

I'm in the midst of trying to clean up my routing. I have a company model that can log in and create applications. They can create several.
Currently this is my setup:
Routes
get 'applications/edit/:id', to: 'applications#edit'
Applications_controller
def edit
#application = current_company.applications.find(params[:id])
end
def update
#application = Application.find(params[:id])
if #application.update(application_params)
redirect_to dashboard_path
else
render 'edit'
end
end
Each company have their own dashboard. Here's my code from
/dashboard
Your active applications
<% #applications.all.each do |f| %>
<%= link_to "Application", show_path + "/#{f.id}" %> | <%= link_to "Edit", edit_application_path("#{f.id}") %>
<br>
<% end %>
Now this all works, if I go to edit_application/11 f.ex I see it.
The thing I'd like changed is to remove the :id from the URL.
Thus make it more secure and to give a nicer feel. Now it took me 5 minutes before I realised I could just change the :id url and edit everything. Thus I added the current_company.applications to stop that. Yet I don't feel like this is very secure.
If you want to remove the :id, you'll still need a way to find the data you want.
As long as you have the url /edit/12 and as long as you use the id 12 in the GET url to find your content, it will show in the browser bar. The only way to "hide" it (but it's not more secure at all, because it's easily found out), is to use a POST request with a form containing a hidden field with the id (can be made in JavaScript).
You are asking the application to get the id from the link in the #applications.all.each but the only way it can do that is to include it somewhere in the request (be it GET, POST, COOKIES/SESSION, ...).
For another (possibly better) solution, read on.
A very common practice is to use slugs: you create a unique key for each content, for example, if your title is "My great app", the slug will be my-great-app. Thus there is no id in your URL (and it cannot be found out if you always use slugs as references). The advantage is that you'll still find a quick match for what you're searching for (creating an unique index on the slugs).
Some further reading about slugs:
http://rubysnippets.com/2013/02/04/rails-seo-pretty-urls-in-rails/
What is the etymology of 'slug'?

Ruby on Rails link_to directing to Index instead of Show

I am having trouble with some Ruby on Rails code. I have a data structure of nested resources (List has_many Tasks and a Task belongs_to a List). On my List.show page, I have the following line of code:
<td><%= link_to 'Show Task', list_tasks_path(#list, task) %></td>
The idea is that this page will link to a "show" page where I can view the details of an individual Task. I want the url to basically be
/lists/:list_id/tasks/:task_id
The problem is that the above code is directing me to
/lists/:list_id/tasks.task_id
on the index page of Task. How can I tell Rails to send me to the show page instead?
I have tried adding :action => show and :controller => tasks, as well as using show_list_tasks_path(#list, task). I also know that the structure itself is there because my show page works fine if I manually enter /lists/:list_id/tasks/:task_id.
Any help is appreciated. Thank you!
-Sum
The problem here is that you're using list_tasks_path when you should be using list_task_path.
The list_tasks_path method will generate a URL to the index action, as you know already, and will make the second argument be the format for this request.
For more information please read the Routing Guide.
A simpler way to specify this url would be
<%= link_to 'Show Task', [#list, task] %>
You can also do list_task_path(#list, task) (notice task instead of tasks).
Run rake routes to see exact names rails generates for your routes.

Using Redirection in New Action in Rails 3

I am trying to construct my first new action in rails, thanks to the help of people here I have now got the vast majority working, but due to my mis-understanding of exactly how things work the action is not performing the desired action.
I have a database called Items, which contains :id, :external_url and :click_count
My goal is to have a link which when clicked on, the user is directed to the external url and :click_count is incremented by 1.
As it stands, I have the following:
view
<%= link_to image_tag( item.picture.to_s + ".gif"), items_clickcountplusone_path(:id => item.id)%>
items_controller
def clickcountplusone
clickeditem = Item.find(params[:id])
redirect_to clickeditem.external_url if clickeditem.update_attribute(:click_count, clickeditem.click_count + 1)
end
routes.rb
get 'items/:id' => 'items#clickcountplusone', :as => :items_clickcountplusone
Using this code, the page itself loads with all the links visible.
However, when I click on a link I get directed to items/whateveridiclickedon NOT the external URL and furthermore the :click_count value does not increase from its initial value.
Am I doing this correctly? In particular is the routes line ok, it currently appears as though i am instructing it to be directed to a specific page on my site for the item, which was not my intention... Also, what is wrong with the if statement meaning the count doesn't increase?
Many thanks for your patience
The mapped route "items/:id" is already associated with the show action and have precedence.
Try associating it with another URL.
get 'items/:id/visit' => 'items#visit', :as => :items_visit

Showing error messages in a redirected request

I am using Authlogic to do some simple signup and login stuff. In my WelcomeController I want to have the signup and login forms on the same page 'index' with form actions set to their individual controllers, UsersController and UserSessionsController, respectively. These controllers redirect the user to the protected profile page within the site on successful signup/login. On error I need to redirect back to the WelcomeController#index and display their errors. Upon doing a redirect this information is lost and I cannot use a render because it is a different controller. What is the correct way to handle this behavior?
I could perhaps store the error messages in the Flash Hash. This seems like the easiest solution.
Lately I have stumbled across this problem in another application I was writing where I needed to render summary pages from researcher submitted RFP forms from a PeerReviewerController. Seemed like in that case the use of now deprecated components would have been the right way to handle this. ie: render_component :controller => 'RFPForms', :action => 'summary', :id => 213
Components seem like the DRY way to do something like this. Now that we don't have them what is the correct solution?
One simple and easy way to do this is to pass a parameter on the redirect:
redirect_to welcome_url(:login_error=>true)
In your view or controller you can then test for that param:
<% if params[:error] -%>
<div class="error">My Error Message</div>
<% end -%>
You could do a render:
render :template => "welcome/index"
But you'd have to make sure that any variables that page expects are loaded, or it won't render.
Drew's answer does not cater for more complex error data (e.g. an array of validation errors), and Marten's answer would risk violating the DRY rule by needing to duplicate code from WelcomeController#index.
A better-looking answer (which is an elaboration on the original poster's idea of storing error data in the flash) is available in Rails validation over redirect although unfortunately I am still personally struggling to get it working ...

Resources