How to refer back to associated index with link_to - ruby-on-rails

Doing nested routes for the first time and I cannot figure out the link_to paths for the nested routes that I have. Using rails scaffold for each
resources :venues do
resources :events
end
I edited to have the following in the index.html.erb of the venue model
<%= link_to 'Events', venue_events_path(venue) %>
Which brings me to the correct index.html.erb of the events model (venues/1/events)
But I just can't seem to figure out the correct link_to path on the show page of event to bring me back to venues/1/events
With the default scaffold, its
<%= link_to 'Back', events_path %>
I have tried different paths like venue_events_path(venue) but rails keeps saying that it cannot find venue without an ID.
I am assuming that is because clicking on the default show link brings me to localhost:3000/events/1 instead of localhost:3000/venues/1/events/1
What would be the correct paths for nested attributes besides the difficulty that I am facing?

For nested routes I would use the following setup:
# routes.rb
resources :venues do
resources :events
end
# venues controller
class VenuesController < ApplicationController
def index
#venues = Venue.all
end
def show
#venue = Venue.find(params[:id])
end
end
# venues index.html.erb
<% #venues.each do |venue| %>
<%= link_to 'Venue', venue_path(venue) %>
<% end %>
# venues show.html.erb
# link to the events index page from the current venue
<%= link_to 'Events', venue_events_path(#venue) %>
# link to each individual event from the current venue
<% #venue.events.each do |event| %>
<%= link_to 'Event', venue_event_path(#venue, event)
<% end %>
# events controller
class EventsController < ApplicationController
def index
#venue = Venue.find(params[:venue_id])
#events = #venue.events
end
def show
#event = Event.find(params[:id])
end
end
# events index.html.erb
# link back to venue
<%= link_to 'Venue', venue_path(#venue) %>
# link to each event
<% #events.each do |event| %>
<%= link_to 'Event', venue_event_path(event.venue, event) %>
<% end %>
# events show.html.erb
# link back to events index
<%= link_to 'Events', venue_events_path(#event.venue) %>
# link back to venue show
<%= link_to 'Venue', venue_path(#event.venue) %>
Keep in mind that this will only work if your events have an venue id. You said you have in your event model: belongs_to :venue, optional: true the optional true make the venue_id not required for an event. If that is what you want then nested routes doesn't really makes sense, because an NOT nested event is not going to be linked nested.

Related

A #search action in a controller refuses to work and erroneously goes to #show

I have a site-wide search form in my application.html.erb. Which is meant to go to the #search action in my controller. Instead, it perpetually attempts to go to #show. I've tried a bunch of hacks to understand why and they're all busts. Any guidance would be most appreciated.
Attempts:
I stripped everything back to research, and just render plain: "OK"
in the controller, going straight to the route in the browser and it
still presents the #show action.
I've restarted the server several times.
Revised the collect do syntax in routes.rb to a one-line hardcoded route get 'lists/search' => 'lists#search', as: 'search_lists'
Checked in the rails console to see if Searchkick works, List.search "*" returns the expected results
I randomly put the def search in the application/controller, not sure why, but I thought I'd see if that did it.
application.html.erb
<%= form_with(url: search_lists_path , method: 'get', local: true) do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag('Search') %>
<% end %>
search.html.erb
<%= content_tag(:h1, "Search Results") %>
<% #list.each do |list| %>
<%= list.name %>
<% end %>
routes.rb
Rails.application.routes.draw do
resources :lists
resources :lists do
collection do
get 'search'
end
resources :products
resources :comments
end
root 'lists#index'
end
controller
class ListsController < ApplicationController
def search
render plain: "OK"
end
def index
#list = List.all
end
def show
#list = List.find(params[:id])
end
Excerpt from rails routes
search_lists GET /lists/search(.:format) lists#search

user_path Not working in association

Ruby on rails application have two model User and Location
User model
belongs_to :location
Location model
has_many :users
routes.rb
devise_for :users
resources :users
This view in location show page
<% #location.users.each do |locuser| %>
<%= link_to locuser.email, user_path %><br>
<% end %>
Error is Couldn't find User with 'id'
This my Users Controller
def show
#user = User.find(params[:id])
end
I added <%= link_to locuser.email, current_user %>
it also not working.
I am considering you are not using devise routes. where no need to pass user object to routes. In your show action you do need id so I am passing user object for show path. If this is not the case run rake routes | grep user and paste log here
it should be user_path(locuser)
try change :
<% #location.users.each do |locuser| %>
<%= link_to locuser.email, user_path(locuser) %><br>
<% end %>
or
<% #location.users.each do |locuser| %>
<%= link_to locuser.email, locuser %><br>
<% end %>

How can I implement a 'create' action without 'new' action

How can I best implement this feature: As an admin, I can assign a Resident Manager to a Hall.
I have a User model with a namespace routing for the admin -I intend on having another namespace routing that would hold the functions of the RM-
I have a Hall model.
Since its a many-many relationship between the above to models, I have a Management join model which contains only user_id and hall_id columns.
I know implementing the above feature, entails creating a new record in the management table but I don't know how to do it. I didn't think using a form (management#new) would solve this because the admin should not know the user_ids/hall_ids...
BELOW IS WHAT I HAVE TRIED TO DO BUT I CAN'T GET IT RIGHT
When the admin gets to the user index page, s/he should see a link for Hall Assignment for each user. This link leads to the management show page for that particular user, which would show the list of halls assigned to that user and also the show all the other remaining halls that isn't assigned to the user. So, either clicking an ADD button or on the hall's name should add it to that user's assigned halls list which is on the same page.
Management#show page
<h2><%= #user.email %>'s assigned halls</h2>
<% #user.managements.each do |management| %>
<%= management.hall.name %>
<% end %>
<p> HALL LISTS </p>
<ul>
<% #halls.each do |hall| %>
<li><%= hall.name %> <%= button_to "Add" %> </li>
<% end %>
</ul>
Here's is my Management controller
class Admin::ManagementsController < ApplicationController
def index
#managements = Management.all
end
def show
#user = User.find(params[:id])
#halls = Hall.all
end
def create
#management = Management.create(managements_params)
redirect_to admin_management_path
end
private
def managements_params
params.
require(:management).
permit(user_id: params[:user_id], hall_id: params[:hall_id])
end
end
And here's a piece of what my routes file looks like:
namespace :admin do
resources :users, only: [:index, :update]
resources :halls, only: [:index, :new, :create]
resources :managements, only: [:index, :new, :create, :show] do
resources :halls, only: [:index]
end
end
Your "add" button is just a mini form (with mostly hidden fields). You can instead just make it an actual form (with the submit-button having the text "Add") and the id-values filled in from the item on the page... it just points to the same routes that you'd normally point the form that you'd find in the new template.
if you want more detail, then show us the code that you have written (rather than a verbal description of it).
Edit:
Ok, so you'd put a button on the page like this
<ul>
<% #halls.each do |hall| %>
<li><%= hall.name %> <%= button_to "Add", managements_path(management: {user_id: #user.id, hall_id: hall.id}, method: :put ) %> </li>
<% end %>
</ul>
Notice the managements_path - you might need to check that that routing is correct (check it against what is in rake routes). Note that you're passing in the user id and the hall id, and that you must set the method to "put" on the button.
First things first -
How can I implement a 'create' action without 'new' action
It's relatively simple to do - you will need a create action somewhere, but a new action is just a way to build the respective ActiveRecord object for your controller.
If you do this in another action, you just have to make sure you point the form to the correct create action (and that create action to redirect back to
--
New / Create
Here's how you could handle the new / create actions in different controllers, as an example for you:
#app/controllers/users_controller.rb
Class UsersController < ApplicationController
def index
#hall = Hall.new
end
end
#app/controllers/halls_controller.rb
Class HallsController < ApplicationController
def create
#hall = Hall.new hall_params
redirect_to users_path if #hall.save
end
private
def hall_params
params.require(:hall).(:hall, :attributes, :user_id)
end
end
This will allow you to show the following:
#app/views/users/index.html.erb
<% #users.each do |user| %>
<%= link_to user.name, user %>
<%= form_for #hall, url: hall_path do |f| %>
<%= f.hidden_field :user_id, value: user.id %>
<%= f.text_field :x %>
<%= f.submit %>
<% end %>
<% end %>
--
Fix
ADD button or on the hall's name should add it to that user's assigned halls list
For this, I don't think you'd need a create action in the "traditional" sense - it will be more about adding new halls to a user's current halls. This is much different than creating a new hall itself:
#config/routes.rb
namespace :admin do
resources :users do
post "hall/:id", to: :add_all #=> domain.com/admin/users/:user_id/hall/:id
end
end
#app/controllers/admin/users_controller.rb
Class UsersController < ApplicationController
def add_hall
#user = User.find params[:user_id]
#hall = Hall.find params[:id]
#user.halls << #hall
end
end
#app/models/user.rb
Class User < ActiveRecord::Base
has_many :user_halls
has_many :halls, through: :user_halls
end
#app/models/hall.rb
Class Hall < ActiveRecord::Base
has_many :user_halls
has_many :users, through: :user_halls
end
#app/models/user_hall.rb
Class UserHall < ActiveRecord::Base
belongs_to :user
belongs_to :hall
end
This uses the ActiveRecord collection methods to make this work, to which you'll be able to provide the following:
#app/views/users/index.html.erb
<% #users.each do |user| %>
<%= link_to user.name, user %>
<%= button_to "Add Hall Test", user_add_hall_path(user, 1) %>
<% end %>

find a post against its description using rails

Friends I just want to show a single post against its description.
On my home page I have all the descriptions and when a user clicks any description then user should be redirected to its respective post.
I have two models one for Post and Descrip.
Descrip belongs_to Post
and
Post has_one Descrip
I just want to know that if user clicks on any description then on next page a post should appear related to that description.
Kindly help or suggest me how i can do that. At this time I just get all the posts when user click a description link. Any help will be highly appreciated. I have partial file which i render to my home page.This partila file have a link button as below
<% #post.reverse_each do |post| %>
<li>
<p>
<%= descrip.description %>
</p>
<%=link_to 'APPLY TO THIS JOB', descriptions_view_path, :class => 'read_more pull_rigt' %>
<% end %>
View.html.erb where i render my partial file look like this
<%= render partial: 'posts/post', locals: { post: Post.all} %>
and posts controller have two methods
def show
redirect_to post_path(Post.all) and return
end
def index
#posts = Post.all(:order => "created_at DESC")
end
and description controller have a view method
def view
#descrip = Descrip.find_by_id(params[:post_id])
#post = Post.all
end
Do this:
#config/routes.rb
root to: "descriptions#index"
resources :descriptions
#app/controllers/descriptions_controller.rb
def index
#descriptions = Description.all
end
def show
#description = Description.find params[:id]
end
#app/models/description.rb
Class Description < ActiveRecord::Base
has_one :post
end
#app/views/descriptions/index.html.erb
<% for description in #descriptions do %>
<%= link_to description.title, description_path(description.id) %>
<% end %>
#app/views/descriptions/show.html.erb
<%= #description.post %>

Using collection_select view helper for objects in a HABTM relationship

The models project and category are in a has_and_belongs_to_many relationship. The partial seen below is used on different views to show a dropdown-menu with all the available categories. The projects in the list below the dropdown-menu are shown according to the choice the user made in the dropdown-menu.
Besides other categories, there is a category named "Everything" that every project is member of. It's also the first entry in the category-db-table, because it got inserted in while loading the migrations into the database.
Right now there is no error, but regardless of which category I choose it reloads the page showing the "Everything" category.
Any idea what I need to change in the code mentioned below to make it work the way I want to? Thanks for your help!
Partial with dropdown-menu and project-list
<!-- category dropdown -->
<% form_for category_url(:id), :html => {:method => :get} do |f| %>
<label>Categories</label>
<%= f.collection_select(:category_ids , Category.find(:all), :id , :name) %>
<%= f.submit "Show" %>
<% end %>
<!-- project list -->
<ul class="projectlist">
<% #projects.each do |_project| %>
<li>
<%= link_to(_project.name, _project) %>
</li>
<% end %>
</ul>
Logoutput after choosing category with id 2 on the dropdown-menu
Processing ProjectsController#index (for 127.0.0.1 at 2009-02-20 17:26:10) [GET]
Parameters: {"commit"=>"Show", "http://localhost:3000/categories/id"=>{"category_ids"=>"2"}}
Category Model
class Category < ActiveRecord::Base
has_and_belongs_to_many :projects, :join_table => "categories_projects"
end
Categories Controller
class CategoriesController < ApplicationController
def show
#projects = Category.find(params[:id]).projects.find(:all)
respond_to do |format|
format.html # show.html.erb
end
end
end
Project Model
class Project < ActiveRecord::Base
has_and_belongs_to_many :categories, :join_table => "categories_projects"
end
Projects Controller
class ProjectsController < ApplicationController
def show
#projects = Project.find(:all)
#project = Project.find(params[:id])
respond_to do |format|
format.html # show.html.erb
end
end
def index
#projects = Project.find(:all)
respond_to do |format|
format.html # index.html.erb
end
end
end
part of 'rake routes' output
category GET /categories/:id {:controller=>"categories", :action=>"show"}
You're passing a parameter called :category_ids, but you're not accessing that anywhere.
form_for category_url(:id)
This will submit your form to the path /categories/1 or whatever id you're currently viewing. You're then using that :id for finding your category projects:
#projects = Category.find(params[:id]).projects.find(:all)
So you're just showing the same ones over again. Because it's a form, you're submitting a query with the :category_ids parameter:
POST /categories/1?category_ids=2
You could just change your Category.find to use the other parameter instead. But, normally to view category 2 you would just use the url /categories/2, where 2 is your :id parameter. You have two ids in that path, and you should decide how you want to resolve that.
One option is to use the categories_path for the form action, and change the collection_select :category_ids parameter to just :id:
/categories?id=2 # from the form
/categories/2 # from a link
But if you're just listing projects, I would move this logic into the projects controller (index action), so your URLs would look like:
/projects?category_id=2` # from the form
/categories/2/projects # from a link
Thanks Andrew, but I solved it myself this way:
I got rid of collection_select, changed to select, added the filter-action (with the according route in config/routes.rb) and now everything works as I expected.
...I'm trying to get an observer on the select-menu, that submits it's value to the filter-action as soon as the user changes the selection in the select-menu, but that's another story. ;-)
New partial with dropdown-menu and project-list
<% form_tag(filter_category_path(:id), :method => :post, :class => 'categories') do %>
<label>Categories</label>
<%= select_tag(:category, options_for_select(Category.all.map {|category| [category.name, category.id]}, #category.id)) %>
<%= submit_tag "Go" %>
<% end %>
<ul class="projects">
<% #projects.each do |_project| %>
<li>
<%= link_to(_project.name, _project) %>
</li>
<% end %>
</ul>
New categories controller
class CategoriesController < ApplicationController
def show
#category = Category.find(params[:id])
#projects = #category.projects.find(:all)
respond_to do |format|
format.html
end
end
def filter
#category = Category.find(params[:category])
#projects = #category.projects.find(:all)
respond_to do |format|
format.html
end
end
end

Resources