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 - ruby-on-rails

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.

Related

How to update an existing record?

I have a Books model and it has CRUD operations. In config/routes.rb, I have declared
map.resources :books
My new.html.erb looks like as:
<%= form_for :book, url: books_path do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.submit :Add %>
<% end %>
My create method in controller looks like as:
def create
book = Book.new(authorized_params)
book.save
end
So, when I submit my form from views, request would go to the 'create' method and an record for the book gets created in database. Fair enough. Now, I want to have an edit page for book. So, my edit method in controller look like as:
def edit
#book = Book.find_by(params[:id])
render :new
end
When I go to my edit view, it automatically show the value of title in the text box, which is what I expected.. But when I try to submit the form again(ofcourse after changing the title value) it again creates a new record instead of updating it..
Something basic which I missed out in my reading? I googled about it though but did not find satisfactory answer.
The issue is that you are using the 'new' view where form has the post method. If you will check the generated routes, post will be for create method, that is adding a new record. You will have to create a new view for edit where the form target URL will be edit_book_path(#book) and method will be patch. Patch method will route to 'update' function in your controller where you will call #book.update. I am not writing the exact code, but these directions should help you achieve what you want

Strong params and action mailer issues

I have tried to create a mailer using the following code:
routes code
resources :listings do
member do
put :lead
end
end
mailer controller code
def lead(listing)
#listing = listing
mail(to: #listing.leadrecepient, subject: "test")
end
standard controller code
def lead
Enquiry.lead(#listing).deliver
end
view
<%= form_for lead_listing_path(#listing), method: :put do |listing| %>
<%= listing.text_field :name %>
<%= listing.submit %>
<% end %>
In the context of a business directory, I want it so that there is a enquiry form on each listing page that when filled out and submitted, the information is sent to the relative listing email.
The problem however is that when I type into the form and click submit, I get the following error:
param is missing or the value is empty: listing
This seems to be because I have it in the "listing" controller which controls the showing and creation of the business listing itself. I therefore have strong params for a new listing which contains all the new listing variables:
def listing_params
params.require(:listing).permit(:fullname, :jobtitle, :email, :franchisename, :leadrecepint, :shortdescription, :longdescription, :website, :branchcount, :scale, :mininvestment, :investmentrange, :category, :hexbg, :logourl, :facebook, :twitter, :linkedin, :googleplus, :approved)
end
How do I go about fixing this? I'm a beginner if I'm honest, could really do with some help to get this mailer working! Thanks.
Strong params are for when you are submitting new resources or modifications to resources. To protect against people adding extra parameters that may circumvent security or other aspects of your application unexpectedly.
If you are adding an action to an existing resource that the user is authorized to access, which this appears to be, you want to just find the object by ID, and use it. So instead of finding it using the params filtered through listing_params, just find it like this in the controller:
def lead
listing = Listing.find(params[:id])
Enquiry.lead(listing).deliver
redirect_to listing
end
And invoke it using a simple link, instead of this:
<%= form_for lead_listing_path(#listing), method: :put do |listing| %>
<%= listing.text_field :name %>
<%= listing.submit %>
<% end %>
Just use this in your view:
= link_to 'Go!', lead_listing_path(#listing), method: :put
Nothing more to it.

Routing a form/create object post request in rails--problems with the form and routing request

I'm pretty new to rails so sorry if this is poorly worded... for a course, I'm creating an app that lets you add (post) new instances of classes called Planets and Moons. Moon is supposed to be a child of Planet. Right now I can create both in separate database tables, using three route requests:
get "planets" => "planets#index"
get "planets/new" => "planets#new"
post "/planets" => "planets#create"
(This create a form page to register new planets. Substitute "moons" and the moon class works the same, including create, from it's own form page.)
I have a fourth route for a planets show-by-id page
get "planets/:id" => "planets#show"
On this planets id show page, I want to create an "Add a moon" form that takes the param ID for the planet, lets the user enter a moon name, and sends the post request to create the new instance.
I don't think I know enough about forms and routing.
My form for the new moons is
<%= form_for #moon, url: "/planets/:id" do |f| %>
<p><strong>New Moon Name:</strong></p>
<p>Name: <%= f.text_field :name %></p>
<% Planet.find(params[:id]: :planet_id %>
<p><%= f.submit "Create!" %></p>
<% end %>
The three "moon" routes I have:
1) get "moons" => "moons#index"
2) get "moons/new" => "moons#new" (goes to a form I was using to test, I don't know if I need this)
3) post "/planets/:id" => "moons#create" (where I think the problem is)
I think I may need to use interpolation to get the planet ID from the params into the moon posting form so help there is great, but I'm more concerned with getting past the line:
<%= form_for #moon, url: "/planets/:id" do |f| %>
I get error: "First argument in form cannot contain nil or be empty"
This is what I have defined in the moons controller...
def new
#moon = Moon.new
end
def create
moon_attributes = params[:moon]
Moon.create({
name: moon_attributes[:name],
planet_id: moon_attributes[:planet_id]
})
end
I hope this question makes sense. Thanks in advance!
To give you some perspective, here's what you need to do:
#config/routes.rb
resources :planets, only: [:index, :new, :create, :show] do
resources :moons, only: [:create] #-> planets/:id/moons
end
This uses the resourceful routing structure in Rails, giving you the paths you have already anyway.
In terms of your form, you'd be best doing this:
#app/views/planets/show.html.erb
<%= form_for #moon do |f| #-> should route to moons_controller#create %>
<p><strong>New Moon Name:</strong></p>
<p>Name: <%= f.text_field :name %></p>
<p><%= f.submit "Create!" %></p>
<% end %>
#app/controllers/moons_controller.rb
class MoonsController < ActiveRecord::Base
def create
moon = Moon.new(moon_params)
moon.save
redirect_to planets_show_path(planet)
end
private
def moon_params
params.require(:moon).permit(:name).merge(planet_id: params[:planet_id])
end
end

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

going against REST conventions in Rails forms

Let me be clearer.
my app has two tables/models: Bikes and Cars
I have a form on page views/cars/index
However, even though the form is in views/cars/index, it has attributes (:pedals and :handlebars) for the Bikes table.
1) Which controller should the form on cars/index with attributes for the Bikes model be submitted to ?
2) What does the form have to look like (in terms of submitting from a view in the Cars index to Bikes model? <%= form_for(#car) do |f| %> OR <%= form_for(#bike) do |f| %>
3) What changes do I have to make to the route when I submit from the index of views/cars/index to insert data into the bikes table? why did I get a missing controller error message when I tried the solution posted by #axsuul
below this line is an earlier (maybe less clear) attempt to explain the problem but i don't think it was clear
this is a form that I have in views/cars/new.html.erb
<%= form_for(#car) do |f| %>
<% if #car.errors.any? %>
and the results are visible in views/cars/show and views/cars/index
However, if I want to submit a form from views/cars/index (Yes I know you don't usually submit from index), and then have it show in a completely different model views/bikes/index, what do I have to change to this?
<%= form_for(#car) do |f| %>
<% if #car.errors.any? %>
If i understand your question right you have a form for creating bikes on your cars/index page.
In that case, create a new bike in the cars controllers index action,
class CarsController < ApplicationController
...
def index
#cars = Car.all
#bike = Bike.new
end
...
end
and use that to create the form,
<%= form_for(#bike) do |f| %>
...
which left like that will be handled by bikes controllers create action.
I still consider this RESTful...
You can choose whatever URL you want to submit to by doing
<%= form_for(#car), :url => create_car_path do |f| %>
for the route
post '/views/cars/index', "cars#index", :as => :create_car
If you are asking to customize which view to render after submitting, you do that in the controller
def index
#car = Car.new(params[:car])
if #car.save
render 'bikes/index'
end
end
Hmm, so from what you explained, you are probably looking for something along the lines of
bikes_controller.rb
def create
#bike = Bike.new(params[:bike])
if #bike.save
redirect_to cars_path and return # this should go back to /cars if successful
end
render 'cars/index' # or render /views/cars/index.html.erb
end
cars_controller.rb
def index
#bike = Bike.new
end
index.html.erb
<%= form_for #bike, :url => create_bike_path do |f| %>
routes.rb
get 'cars' => "cars#index", :as => :cars
post 'cars' => "bikes#create", :as => :create_bike

Resources