Link_to to update attribute in table - ruby-on-rails

I want a link to update a resource, without using an HTML form.
I have a Kanban board listing projects grouped by their status. Via the click of a button I want to update the status of a project moving them to the next list. This should happen on the workflows index: /tenants/{id}/workflows
Problem
The button_to or link_to seems to be feasible avoiding a form, but I don't know which route and params to use in the index.html.erb. Any advice would be much appreciated.
Routes
resources :tenants do
resources :members
resources :projects
resources :workflows
end
Workflows/index.html.erb
<%- model_class = Project -%>
<% #projects.where(tenant_id: #tenant.id, :status => "Nominated").each do |project| %>
<%= project.title %>
<%= button_to "Update", XXXX, method: :put, params: { status: "In Progress" } %>
<% end %>
<% end %>

Related

Rails 5. How to submit from the form_tag to custom action?

I'm a real newbie at Ruby and Rails, and I've been looking for the solution for two days. I need to submit data from form_tag to action 'create' in my controller to add new entries to database, but looks like I'm doing something terribly wrong, because absolutely nothing happens, and it seems that form_tag doesn't even redirect to needed action.
Here's the page code:
<h1>Todos</h1>
<% #projects.each do |project| %>
<tr>
<h2><%= project.title %></h2>
<% project.todos.each do |todo| %>
<ul style="list-style-type:disc">
<li><%= todo.text %></li>
</ul>
<% end %>
</tr>
<% end %>
<%= form_tag({controller: "mega", action: "create"}, method: "get", remote: true) do %>
<h2>New todo</h2>
<p>
<%= text_field_tag 'text' %>
</p>
<p>
<%= select_tag 'title', options_from_collection_for_select(#projects, 'id', 'title') %>
</p>
<p>
<%= link_to 'CANCEL' %>
<%= link_to 'OK', "", :onclick => "$('#form_id').submit()" %>
</p>
<% end %>
And the controller:
class MegaController < ApplicationController
def index
#projects = Project.all
#todos = Todo.all
end
def update
end
def create
#newTodo = Todo.create(text: params[:text])
#newProject = Project.find_by(title: params[:title])
#newProject.todos << #todo
#newTodo.save
end
end
My routes file. I seriously don't know how it works:
Rails.application.routes.draw do
get 'mega/index'
root 'mega#index'
get 'mega/update'
post 'mega/create'
resources :todos
resources :projects
end
You create resources with a POST request. Never GET.
GET requests should be idempotent - they should not update or alter resources on the server. One very important reason is that they are stored in the browser's history, so pressing the back button will cause unintended consequences for the user.
In Rails flavor MVC instead of tacking the action name on the path of the route you use the HTTP verb to create routes to the correct action:
GET /things things#index
POST /things things#create
I'm not going to attempt to salvage your code (it's deeply flawed) and instead show you how you would solve this the rails way as it is much simpler:
<%= form_for(Todo.new) do |f| %>
<h2>New todo</h2>
<%= f.text_field :text %>
<%= f.collection_select(:project_id, #projects, :id, :title, prompt: true) %>
<%= f.submit %>
<% end %>
This would submit to todos#create - if you want to route it to an unconventional action you can use the url option:
<%= form_for(Todo.new, url: polymorphic_path(controller: 'foo', action: 'bar')) do |f| %>
It's best to learn the rules before you break them.

Link_to path in each do loop not working

In this Rails app, Users write Stories. A Story may be part of a Collection. Collections belong to the User who created it.
I am trying to show a single Story with links to the Collections it is part of. The collection.name part works but I can't get the collection_path right. Thanks for your help.
stories/show.html.erb
<% #story.collections.each do |collection| %>
<%= link_to collection.name, collection_path %>
<% end %>
rake routes for collections
user_collections GET /users/:user_id/collections(.:format) collections#index
POST /users/:user_id/collections(.:format) collections#create
new_user_collection GET /users/:user_id/collections/new(.:format) collections#new
edit_user_collection GET /users/:user_id/collections/:id/edit(.:format) collections#edit
user_collection GET /users/:user_id/collections/:id(.:format) collections#show
routes.rb
resources :users do
resources :collections
Solved it by using the following with the help of Sebastián Palma who answered this earlier.
<% #story.collections.each do |collection| %>
<%= link_to collection.name, user_collection_path(collection.user, collection), class: 'btn btn-lake' %>
<% end %>

Rails route to a resource

I'm building a Rails app that is a podcast directory. I have Podcasts and Episodes. Episode belongs to Podcast and Podcast has many Episodes. On the home page I want to show the last 5 episodes that have been created and link to them.
I have it working with this, though this is obviously not the way to do it:
<% #episodes.each do |episode| %>
<%# link_to episode do %>
<%= episode.title %>
<%# end %>
<% end %>
The link_to is commented out because that's part of my problem.
Here is the index controller:
def index
#podcasts = Podcast.where.not(thumbnail_file_name: nil).reverse.last(5)
#episodes = Episode.where.not(episode_thumbnail_file_name: nil).reverse.last(5)
end
Here is the routes file:
Rails.application.routes.draw do
devise_for :podcasts
resources :podcasts, only: [:index, :show] do
resources :episodes
end
authenticated :podcast do
root 'podcasts#dashboard', as: "authenticated_root"
end
root 'welcome#index'
end
Results of rake routes | grep episode:
podcast_episodes GET /podcasts/:podcast_id/episodes(.:format) episodes#index
POST /podcasts/:podcast_id/episodes(.:format) episodes#create
new_podcast_episode GET /podcasts/:podcast_id/episodes/new(.:format) episodes#new
edit_podcast_episode GET /podcasts/:podcast_id/episodes/:id/edit(.:format) episodes#edit
podcast_episode GET /podcasts/:podcast_id/episodes/:id(.:format) episodes#show
PATCH /podcasts/:podcast_id/episodes/:id(.:format) episodes#update
PUT /podcasts/:podcast_id/episodes/:id(.:format) episodes#update
DELETE /podcasts/:podcast_id/episodes/:id(.:format) episodes#destroy
How can I correctly create a text link of the title using a link_to that links directly to the episode? Thanks!
When you're using link_to with a block, the only thing you need to pass into the block is the text of the link, so you should be able to do this (assuming your routes are setup properly):
<% #episodes.each do |episode| %>
<%= link_to episode, class="tt-case-title c-h5" do %>
<%= episode.title %>
<% end %>
<% end %>
UPDATE
You really don't even need to use a block here. This should work fine for you and be a little more succinct.
<% #episodes.each do |episode| %>
<%= link_to episode.title, episode, class="tt-case-title c-h5" %>
<% end %>
UPDATE #2
Thanks for including your route info. Try this:
<% #episodes.each do |episode| %>
<%= link_to episode.title, podcast_episode_path(episode.podcast, episode), class="tt-case-title c-h5" %>
<% end %>

How to abstract link_tos for nested resources on multiple models

I have a nested resource in a Rails 3.2 app.
resources :users do
resources :posts
end
resources locations do
resources :posts
end
resources categories
resources :posts
end
In a shared sidebar module displayed on User, Location and Category show pages I have a link to the nested resource
<% if controller.class == UsersController %>
<%= link_to "Posts", user_posts_path(#user) %>
<% elsif controller.class == LocationsController %>
<%= link_to "Posts", location_posts_path(#location) %>
<% elsif controller.class == CategoriesController %>
<%= link_to "Posts", category_posts_path(#category) %>
<% end %>
Is there a clever way to DRY this up? I'm thinking something like <%= link_to "Posts", controller_name_posts_path(#current_object) %>
It's not as clever as that but I'd simplify as a first step by defining #resource_path (actually I'd probably expose a method) in each controller so that the view template is simplified to something like
<%= link_to "Posts", #resource_path %>
In the controller action - something like:
#resource_path = user_posts_path(#user)
or similar
Using content_for(or just provide) should do the trick as well.
Without touching your controller add call to content_for at the top of your view show files:
example for users/show:
<% content_for :resource_path, user_posts_path(#user) %>
In your shared sidebar module change your block of code to:
<%= link_to "Posts", yield :resource_path %>

link_to with Namespaces in Rails

I'm trying to get an admin interface working in Rails, but I'm having trouble using link_to with the nested routes. I'm trying to get a link to /admin/cake_class/:id but it's sending me to admin/cake_class.:id instead.
config/routes.rb:
namespace :admin do
resources :cake_class
end
/app/views/admin/cake_class/index.html.erb
<h1>all classes</h1>
<% #classes.each do |c| %>
<%= c.date %>
<%= c.name %>
<%= link_to 'Show', admin_cake_class_path(c) %>
<% end %>
Any suggestions?
The :resources should be plural, :cake_classes, which could be tripping you up.
What does the output of rake routes show?

Resources