How to search all nested resources without the parent resource? - ruby-on-rails

My app's got Listings nested within Categories.
I can search all the listings when I'm in a particular category with this form:
<%= form_tag category_listings_path(#category), method: :get do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag 'Search', name: nil %>
</p>
<% end %>
As you can see, I must make a get request to the category_listings_path and pass in the current Category.
However, this method fails when I want to put the search bar on a page where no Category exists!
How can I search for all Listings without needing to pass in a Category?

Based on what you wrote, I'm guessing your routes look something like:
resources :categories do
resources :listings
end
This means that all of your routes for listings require a category id. If you want a path for all listings, regardless of category, add:
resources :listings, only: [:index]
to your routes. Then you can have a form that searches to listings_path (which is the path that above route creates) and you don't need a category id.

Related

Rails has_many through association delete path

I have a place model and a user model and a user_place model, user_place belongs to user and place both. Traditional has_many through association.
I have a page where you can view the users associated with a place. My routes look like:
resources :places do
resources :user_places
end
which generates these routes:
place_user_places GET /places/:place_id/user_places(.:format) user_places#index
POST /places/:place_id/user_places(.:format) user_places#create
new_place_user_place GET /places/:place_id/user_places/new(.:format) user_places#new
edit_place_user_place GET /places/:place_id/user_places/:id/edit(.:format) user_places#edit
place_user_place GET /places/:place_id/user_places/:id(.:format) user_places#show
PATCH /places/:place_id/user_places/:id(.:format) user_places#update
PUT /places/:place_id/user_places/:id(.:format) user_places#update
DELETE /places/:place_id/user_places/:id(.:format)
I don't love this but I'm ok with it for now.
But whenever I try to delete a user_place I have all sorts of issues.
<%= link_to "delete", place_user_place_url(place_id: #user_place.place_id, id: #user_place.id), method: 'delete' %>
No route matches {:action=>"show", :controller=>"user_places", :id=>nil, :place_id=>2}, possible unmatched constraints: [:id]
I had this working previously with slightly different routes and an actual form:
resources :places do
resources :user_places, as: 'user', only: %i[index create new]
delete 'remove_user', to: 'user_places#remove_user'
end
<% if user != current_user %>
<%= form_with model: #user_place, url: place_remove_user_path(#place.id), method: 'delete' do |form| %>
<%= form.hidden_field :user_id, value: user.id %>
<%= form.hidden_field :place_id, value: #place.id %>
<%= form.submit "delete" %>
<% end %>
<% end %>
But this feels hacky, I don't think I should need a specific form, and this was leading the form to be submitted with javascript which I don't want.
What might be a solution is to use shallow nesting in the routes (shallow: true).
resources :places do
resources :user_places, shallow: true
end
Make sure to run rails routes again. The delete method of a user_place will no longer be nested.
You can then simply delete the user_place passing a single variable (an instance of a user place, #user_place). There is no need to set the id (place_id or id) as Rails is smart enough to handle that. Just passing an instance variable is enough for the delete method to find the corresponding record.
<%= link_to "delete", user_place_url(#user_place), method: 'delete' %>

open child form in new page

I have a sponsor which can have many warranty management urls. I have implemented the sponsor form but having trouble to create urls child form. Problem is I need to create child in new page and show the list back to the main form. How do I do it?
My form:
<%= form_for #sponsor, url: polymorphic_path([:a, #sponsor]) do |form| %>
<%= form.file_field :logo %>
<%= link_to "Add Warranty Service URL", new_a_sponsor_warranty_management_url_path(#sponsor), class: 'button green right' %>
<% end %>
Routes:
resources :sponsors do
resources :warranty_management_urls, only: [:new,:edit,:create,:update,:destroy]
end
Controller:
def new
#sponsor = Sponsor.new
end
Currently this error pops up:
No route matches {:action=>"new", :controller=>"a/warranty_management_urls", :sponsor_id=>nil}, possible unmatched constraints: [:sponsor_id]
It looks like your route helper is incorrect. The documentation for resource route helpers may be helpful for your situation: https://guides.rubyonrails.org/routing.html#path-and-url-helpers
Have you tried running rake routes to get the list of available routes and route helpers? I imagine you need something more like:
<%= link_to "Add Warranty Service URL",
new_warranty_management_url_path,
class: 'button green right' %>
You can pass a sponsor_id param as an argument to the path helper, but that won't work unless the sponsor has been saved, which isn't true for a new record.

Trying to fire an action in my controller when a selection in a drop down menu is made but getting a no route matches error

I'm building a web interface to accompany a mobile app I'm building. I have a drop down select menu that lists a bunch locations.
On selection of a location I want to make a call to a method in my controller and grab some destinations within the location that was selected (each location has several destinations).
I then would like to render my show template with these results allowing the user to select a destination and make a booking.
This is what I have so far:
My view with a list of resorts:
<%= form_tag :url => { :action => :show } do %>
<%= select_tag :resort , options_for_select(#resorts), :prompt => 'Select Resort', :onchange => 'submit()' %>
<% end %>
Controller:
class HomeController < ApplicationController
def index
#resorts = ["A","B", "C", "D", "E"]
end
def new
end
def edit
end
def create
end
def show
#activities = Parse::Query.new("Activity").tap do |a|
a.eq("resort", params[:resort])
end.get
end
end
Just slightly confused. Using form_for makes more sense to me with CRUD in mind and also because the form is object based.
I'd like to just take the selected resorted and pass it into a method in my controller that goes into a database and grabs a bunch of destinations. I then want to list these destinations on my show page where a user can click and be taken to another page where they can make a booking at that destination.
My above code doesn't work. I have resources :home in my routes file.
However when I try to load my page with the form I get:
No route matches {:action=>"show", :controller=>"home"} missing required keys: [:id]
How do I pull this off?
I went on my lynda account and pulled up a rails essential tutorial which I'll have to use to refresh my memory some time tomorrow but the tutor doesn't cover use of select_tag.
Would appreciate some help here
Thanks for your time
So a few thoughts. Not sure why you are using form_tag and also not sure why you aren't using Rails idiomatic conventions.
Declare a resource in your routes for #resorts, like so:
resources :resorts
Then just use Rails form_for helper like:
<%= form_for #resorts, url: {action: "create"}, html: {class: "nifty_form"} do |f| %>
<%= f.select :resort, (insert your other options) %>
<%= f.submit "Create" %>
<% end %>
I have not tested the above code, so play around with it, but that should work.
However, let me save you some headache. Checkout SimpleForm.
For your models, you would want to setup an association between your locations and destinations.
class Location < ActiveRecord::Base
belongs_to :resort # or whatever the relation is
has_many :destinations
end
class Destination < ActiveRecord::Base
belongs_to :location # This assumes there is just a one-to-many relationship between Location and Destination
end
Make sure you have a LocationsController with all the actions.
In this case, your SimpleForm form would look something like this:
<%= simple_form_for #locations do |f| %>
<%= f.input :name %>
<%= f.association :password %>
<%= f.button :submit %>
<% end %>
That approach will make your life much easier. Take a look at the collections methods in Simple Form. Rails can make your life difficult with the built in form helpers.
Hope that helps!
In your routes, add
get '/choose_resort' => 'home#show' #you can name the get whatever
Then in your form...
<%= form_tag choose_resort_path do %>
That being said... you should have your query at a separate endpoint, and redirect to the show page. That should get you moving, methinks.
The show action needs an id of the object you are showing. Change your controller:
class HomeController < ApplicationController
def index
#resorts = [["A",1], ["B",2], ["C",3], ["D",4], ["E",5] ]
end
And your view
<%= select_tag :id , options_for_select(#resorts), :prompt => 'Select Resort', :onchange => 'submit()' %>
That gives your show action the proper resort id. You'll have to adjust that action to find the right activities relevant to the resort.

Trouble with Rails ActiveRecord relationships and adding a record for one model within another models view

I put all the code in this gist because I can't get the formatting to work.
https://gist.github.com/anonymous/72e66308c236a0277943
What I am trying to do is to have a form for the prof_comments model on the Professors page.
Whenever I try and submit the form I currently have for the prof_comments model, it tries to post to the current professors show page (/professors/1)
I've been trying to follow the following StackOverflow posts, but no luck yet.
Rails: Show form from different model in a view
Possible to add a form into another models view in rails
Routes.rb
Rails.application.routes.draw do
root :to => "welcome#index"
devise_for :users
resources :users
resources :professors
resources :prof_comments
resources :classes
resources :class_comments
end
I'm not sure about the approach you were trying but this will do exactly what you are trying to do: have the professor's comments appear under it's show page.
You can nest prof_comments under professors
your routs will look like this:
resources :professors do
resources :prof_comments, shallow: true
end
prof_comments controller:
def create
#professor = Professor.find(params[:id]) #this pulls specific professor by :id
#prof_comment = #professor.prof_comments.create(prof_comment_params)
redirect_to professor_path(#professor) # this will rout you to professor's show page once the comment is created.
end
end
in app/views/professors/show.html
h2>Add a comment:</h2>
<%= form_for([#professor, #professor.prof_comments.build]) do |f| %>
<%= f.label :commenter %><br> #commenter with the actual attribute_name
<%= f.text_field :commenter %> #commenter with the actual attribute_name
<%= f.label :body %><br> #body should be replaced with your actual attribute_name
<%= f.text_area :body %> #body should be replaced with your actual attribute_name
<%= f.submit %>
<% end %>
these comments will appear under the professor show view. the comments are nested under it. Treat the professor's controller as usual. you'll be using to create the comments using prof_comments controller.
You have to use
form_for #prof_comment
with # not :

Rails Controllers - Adding a Custom Action

I have an Article resource and have defined resourceful routes for it. I want to create a simple page that shows the articles of the current user. I am aware that it is possible to do so by adding another action, for example 'search' to articles controller which will contain the custom code that searches for articles that have the same user id. And for the routes:
resources :articles do
get 'search'
end
But I'm not sure if adding a custom action is a good idea in this case. I'm thinking I can still use the index action (which shows all articles) and pass some sort of parameter from the url so that it can distinguish if the user wants to see all articles or just his own. But I'm not sure exactly how this can be done. Any help would be great. Thanks!
You can use the query string to pass parameters. see here
So you can pass something like .../articles?user_id=2
In your controller, just change the behavior according to the user_id parameter.
you don't need to create a new action/view for it.
You can add a small form to filter all articles or only my articles, for example:
<%= form_tag articles_path, method: :get do %>
<%= radio_button_tag :search, "all", :checked => true %>
<%= label_tag :all %><br />
<%= radio_button_tag :search, "my" %>
<%= label_tag :my_articles %><br />
<%= submit_tag "filter", name: nil %>
<% end %>
than in your controller:
def index
if params[:search] == 'my'
#articles = current_user.articles
else
#articles = Article.all
end

Resources