Rails: Routing and form for custom controller method - ruby-on-rails

I'm getting this error attempting to create a page that shows room details. Pressing on edit will triggger a popup window with prefilled values of the room clicked. And clicking save on the window will update data for that entry.
I'm not so sure how to predefine the id, I'm currently using jQuery to populate the form with current data of selected records.
No route matches {:action=>"save_details", :controller=>"rooms"}, missing required keys: [:id]
rooms/index.html.erb
<%= form_for(#room, url: save_details_room_path) do |f| %>
<% f.text_field :id, id:'edit-room-id', class:'d-none' %>
<% f.text_field :name, id:'edit-room-name' %>
<% f.text_area :desc, id:'edit-room-desc', style:'width: 90%; height: 8em; resize: none; float: bottom' %>
<%= f.submit 'Save', :class=>'btn btn-primary' %>
<% end %>
rooms_controller.rb
def save_details
logger.info ('Hello world')
#room= Room.find(params[:id])
#room.name = params[:name]
#room.description = params[:desc]
#room.save
redirect_to rooms_url
end
def show
#room = Room.find(prams[:id])
end
def index
#room = Room.all
end
routes.rb
resources :rooms do
get :save_details, on: :member
end
main.js
const name = $(this).data('name');
const desc = $(this).data('description');
const id = $(this).data('id');
$('#edit-room-id').val(id);
$('#edit-room-name').val(name);
$('#edit-room-desc').val(desc);
1ST EDIT:
Now I'm doing this another way which is just to simply pass the form as a url through, eg. /rooms/save_details?id=1,name=123,desc=1234. However the form just simply routes it into the default show/index methods in my controller. Anyway to route it directly to save_details method? Doing the below simply returns the error that says save_details does not exist as an id. Also editted my routes
new routes.rb
get '/rooms/save_details/:id/:name/:desc' => 'rooms#save_details', :as => 'save_details'
index.html.erb
<form action="rooms/save_details" method="get">
....
</form>

Looks like you're trying to save a form, this probably shouldn't be a get
resources :rooms do
post :save_details, on: :member
end

You're missing the :id parameter on your route helper. You need to do:
<%= form_for(#room, url: save_details_room_path(id: #room.id)) do |f| %>
And as Asthmatic suggested, that will have to be a :post route if a form is being submitted to it.
It appears you're using jQuery to fill in the room id, so you may have to skip the Rails form helper in favor of a plain HTML form. In that case you'll have to build and add the action attribute after you have the room id.

Finally solved it by using a normal HTML form and adding the following in routes.rb
get '/rooms/save_details/:id/:name/:desc' => 'rooms#save_details', :as => 'save_details'
resources :rooms do
get 'save_details', on: :collection
end

Related

undefined method `posts_path' for #<#<Class:0x007fe3547d97d8>:0x007fe3546d58f0>

I'm new to rails and I'm getting this error:
undefined method `posts_path' for #<#<Class:0x007fe3547d97d8>:0x007fe3546d58f0>
I've posted my files below, please keep in mind I'm new to rails so simple explanations would be really appreciated!
Route.rb:
Rails.application.routes.draw do
get '/post' => 'post#index'
get '/post/new' => 'post#new'
post 'post' => 'post#create'
end
post_controller.rb:
class PostController < ApplicationController
def index
#post = Post.all
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to '/post'
else
render 'new'
end
end
private
def post_params
params.require(:post).permit(:content).permit(:title)
end
end
new.html.erb:
<%= form_for(#post) do |f| %>
<div class="field">
<%= f.label :post %><br>
<%= f.text_area :title %>
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit "Create" %>
</div>
<% end %>
I'm guessing form_for(#post) expects there to be a method called posts_path and one doesn't exist because it hasn't been defined in your routes file. Try replacing:
Rails.application.routes.draw do
get '/post' => 'post#index'
get '/post/new' => 'post#new'
post 'post' => 'post#create'
end
with
Rails.application.routes.draw do
resources :posts, only: [:new, :create, :index]
end
Edit: more info:
Read the full page on form helpers at http://guides.rubyonrails.org/form_helpers.html, and inparticular, read the section on "2.2 Binding a Form to an Object" and the part that says:
When dealing with RESTful resources, calls to form_for can get
significantly easier if you rely on record identification. In short,
you can just pass the model instance and have Rails figure out model
name and the rest:
## Creating a new article
# long-style:
form_for(#article, url: articles_path)
# same thing, short-style (record identification gets used):
form_for(#article)
## Editing an existing article
# long-style:
form_for(#article, url: article_path(#article), html: {method: "patch"})
# short-style:
form_for(#article)
Notice how the short-style form_for invocation is conveniently the
same, regardless of the record being new or existing. Record
identification is smart enough to figure out if the record is new by
asking record.new_record?. It also selects the correct path to submit
to and the name based on the class of the object.
So, knowingly or not, when you say form_for(#post), you're asking rails to guess the route that your form should be submitted to, based on the name of your #post variable. The routes that you had defined didn't match what rails expected them to be.
For more on routing in rails read the entire page at http://guides.rubyonrails.org/routing.html, and inparticular pay attention to the section "2 Resource Routing: the Rails Default". Your form_for(#post) will assume that you're using "resource routing", which is what I switched to.
As for why your getting a new error? There's somewhere else in your app where you were expecting to use your previous custom defined routes, and now you're using rails "resource routes" so your path names will be different. No route matches [GET] "/post/new" because now the route instead matches No route matches [GET] "/posts/new" (note the plural posts).
Here the form is try to find a route to a post_method through a path "posts_path"
So you need to define in your routes.rb file.
Rails.application.routes.draw do
get '/post' => 'post#index'
get '/post/new' => 'post#new'
post '/posts' => 'post#create'
end
The problem arises from the views. Rails cannot recognize the path that will run when the form is submitted.
You can manually change your form_for tag to point to the appropriate url.
<%= form_for #post, :url => "enter_your_path_here" do |f| %>
This solved my similar problem
you need to rename the post controller and the corresponding files to plural. that's posts not post. and then the route too needs to be resources :posts.
don't forget to change the class name of your post controller to be plural.

Update attributes rails - No route matches [POST]

I'm trying to basically update my integration object attribute "filters". I have a integrations controller and what seems the proper actions to do so. But when I try to save after filling out the text-field I get this error No route matches [POST], I understand what it's saying but isn't update a post? Here is my code for clarity.
Controller
def update
#integrations = current_account.integrations.find(params[:id])
attrs = params.require(:integration).permit(:filters)
if #integrations.update_attributes(attrs)
redirect_to account_integration_path
else
render :filters
end
end
def filters
#integrations = current_account.integrations.find(params[:id])
end
View
<%= form_for #integrations, url: filters_account_integration_path do |f| %>
<%= f.text_field :filters, class: "tag-autocomplete" %>
<%= link_to "Save", account_integration_path, method: :post, class: [ "button", "button--modal" ] %>
<% end %>
Routes
resources :integrations, only: [ :index, :destroy, :update ] do
get "filters", on: :member
end
Hopefully that is enough info let me know if you need more? My basic question is why is this not updating the integration object? Isn't update a post?
resources generates seven routes by default. You're using it to generate only three of those. Those three routes will look like this:
GET /integrations
DELETE /integrations/:id
PATCH /integrations/:id/edit
Your form, on the other hand, is trying to use this route:
POST /integrations/:id
which doesn't match any of the generated routes.
Instead, try using the default form helpers:
<%= form_for #integrations, url: url_for(:controller => :integrations, :action => :update, :id => #integrations.id) do |f| %>
<%= f.text_field :filters, class: "tag-autocomplete" %>
<%= f.submit "Save" %>
<% end %>
That's assuming that #integrations is a single Integration resource. If it isn't, you have bigger problems than just this.

Where and how to set form for nested resources in rails?

I have an Idea model, which has one Chat, and of course, this chat has messages.
Based on the following routes, I want to create a form in the chat page to post messages.
# Chat belongs_to :idea, and Chat has_many :chat_messages
# I wan't to post messages to /idea/:id/chat/chat_messages
resources :ideas do
resource :chat, only: :show do
resources :chat_messages, only: :create
end
end
For now, my form is in app/views/chats/show.html.erb and looks like that :
# #chat and #chat_message are defined in Chat controller but I put them here so you can see them
#chat = Chat.where(idea_id: params[:idea_id]).first
#chat_message = ChatMessage.new(chat: #chat)
<%= form_for [#chat.idea, #chat, #chat_message] do |f| %>
<%= f.text_area :body, size: "60x12" %>
<%= f.submit "Message" %>
<% end %>
The form generates the following html (I have removed the inputs and some content which was not relevant) :
<form action="/ideas/1/chat/chat_messages.1" accept-charset="UTF-8" method="post">
</form>
Why is there .1 in my form action ? (it causes error). How should it be ? i need it to access /ideas/1/chat/chat_messages
Try this,
form_for [:idea, #chat, #chat_message]

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.

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

Resources