I hope the title, a blend of code and English, is sufficiently clear.
I have found very little documentation about this situation in my web searches... It seems even the official rails API guide and doc doesn't cover a form_for with a model that belongs to another.
I'm new to RoR, and it's fun! I am working with relationships and trying to create the form to make a new 'item' on a 'contest'. The problem is it is coming out completely blank, no HTML rendered whatsoever inside the body tags where the form should be.
Here is my routes.rb
resources :contests do
resources :items do
resources :votes
end
end
My item#new
def new
#contest = Contest.find params[:contest_id]
#item = Item.new
end
My new.html.erb
<%= render 'form', item: #item %>
And my form_for
<% form_for #item, url: {action: "create"} do |f| %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :notes %>
<%= f.text_area :notes %>
</div>
<% end %>
Also, here is the route display
contest_item_votes_path GET /contests/:contest_id/items/:item_id/votes(.:format)
votes#index
POST /contests/:contest_id/items/:item_id/votes(.:format)
votes#create
new_contest_item_vote_path GET /contests/:contest_id/items/:item_id/votes/new(.:format)
votes#new
edit_contest_item_vote_path GET /contests/:contest_id/items/:item_id/votes/:id/edit(.:format)
votes#edit
contest_item_vote_path GET /contests/:contest_id/items/:item_id/votes/:id(.:format)
votes#show
PATCH /contests/:contest_id/items/:item_id/votes/:id(.:format)
votes#update
PUT /contests/:contest_id/items/:item_id/votes/:id(.:format)
votes#update
DELETE /contests/:contest_id/items/:item_id/votes/:id(.:format)
votes#destroy
contest_items_path GET /contests/:contest_id/items(.:format)
items#index
POST /contests/:contest_id/items(.:format)
items#create
new_contest_item_path GET /contests/:contest_id/items/new(.:format)
items#new
edit_contest_item_path GET /contests/:contest_id/items/:id/edit(.:format)
items#edit
contest_item_path GET /contests/:contest_id/items/:id(.:format)
items#show
PATCH /contests/:contest_id/items/:id(.:format)
items#update
PUT /contests/:contest_id/items/:id(.:format)
items#update
DELETE /contests/:contest_id/items/:id(.:format)
items#destroy
Here we go! My form_for call is inside a non-output tag. Changing <% to <%= reveals the output!
It seems that sometimes the answers to my questions end up being tiny details that are easy to miss when the problem seems complex. A word to those who stumble through here: consider the basics before re-iterating the complexities.
Related
I am creating a Rails app, and I need a form to function in one of my views and submit data to a table without the use of a scaffold (like I usually do).
Now, the place where this comment form is going to appear is in one view within the blog folder. It will need to allow the user to put in their comment, save it to the table, and then return to the same page.
While this is a pretty commonplace error, I am confused because I am specifying two things that seem critical: creating resources in my routes file for the form, and second, using a create method in my controller.
In the blog.html.erb, this happens in this form:
<%= form_for :cements do |f| %>
<div class="form-group">
<div class="field">
<%= f.label :post %><br>
<%= f.text_area :post, class: "form-control" %>
</div>
</div>
<h5 id="username">Username</h5>
<div class="form-group">
<div class="field">
<%= f.text_field :username, class: "form-control" %>
</div>
</div>
<%= f.hidden_field :slug, :id => "hiddenPicker"%>
<div class="actions">
<%= f.submit "Save", class: "btn btn-success-outline" %>
</div>
<% end %>
Then, in my controller, I have a create method that should redirect back to the original page, as I wanted.
blogs_controller.rb
class BlogsController < ActionController::Base
def index
#posts = Post.order('updated_at DESC').all
#comments = Cement.all
end
def blog
#posts = Post.where(slug: params[:id]).all
#comments = Cement.all
end
def create
#cements= Cement.new(story_params)
#cements.save
redirect_to(:back)
end
private
def story_params
params.require(:cements).permit(:username, :post, :slug)
end
end
Good news: the comment form renders in the view. Bad news: when I submit, I am getting this error: No route matches [POST] "/blog".
My expectation is this will be an issue with my Routes file; however, I have a resources method already in there:
Rails.application.routes.draw do
resources :posts
resources :cements
resources :blogs
The naming convention is the same as my controller file, so I am confused why this error is happening. Any ideas?
:cement is not an object it is just a symbol, so how rails will determine where to POST form? If you inspect your form you will see form action as /blog (current page url).
You should either do
<%= form_for :cements, url: cements_path do |f| %>
or
<%= form_for Cement.new do |f| %>
Both of above will generate form action as /cements, which will submit to CementsController create action, But I see in your case you want to submit it to BlogsController so use the appropriate routes(blogs_path). You can use url in second version also.
I'm having an issue very similar to the one asked in this question here: NoMethodError / undefined method `foobar_path' when using form_for However the answer there confuses me.
I went through Michael Hartel's Ruby on Rails tutorial before developing the application I'm working on at the moment, I tried to copy exactly what he did when he created a user model as I created my model. My application is designed to be a database for university professors, so the model I'm using is called "professor" but it's the same concept as "user".
Here is the code for my New.html.erb where is where users go to create a new professor:
<%provide(:title, 'Add a professor') %>
<div class="jumbotron">
<h2> New Professor</h2>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for (#professor) do |f| %>
<%= f.label "First Name" %>
<%= f.text_field :fname %>
<%= f.label "Last Name" %>
<%= f.text_field :lname %>
<%= f.label "School" %>
<%= f.text_field :school %>
<%= f.submit "Add this professor", class: "btn btn-primary" %>
<% end %>
</div>
</div>
</div>
And then here is the code from the Professor_controller.rb
class ProfessorController < ApplicationController
def show
#professor = Professor.find(params[:id])
end
def new
#professor = Professor.new
end
end
When I replace
<%= form_for (#professor) do |f| %>
In new.html.erb with:
<%= form_for (:professor) do |f| %>
It works. The thread I mentioned above said something about adding a route for the controller. My routes.rb looks like this:
Rails.application.routes.draw do
root 'static_pages#home'
get 'about' => 'static_pages#about'
get 'newprof' => 'professor#new'
resources :professor
And I don't believe that in Michael Hartel's book he does anything differently. I'm still very new to Rails so forgive me if this is a bit of an easy question, I've been stuck on it for a few days and I've tried numerous work arounds, using the instance of :professor works but #professor does not and I don't know why.
Within the Rails environment it's very important to be aware of the pluralization requirements of various names. Be sure to declare your resources as plural:
resources :professors
Declaring it in the singular may mess up the automatically generated routes, you'll get thing like professor_path instead of professors_path. You can check what these are with:
rake routes
If you get errors about x_path being missing, check that there's a route with the name x in your routes listing. The most common case is it's mislabeled, a typo, or you've failed to pluralize it properly.
I'm in need of some help regarding setting up the routing (I think that is the problem) for a view that is set up with bootstrap tabbed navigation. What I want to do is set up a form in each tab. Sounds easy enough.
However I can't figure out how the routing works when you want to submit two different actions (one to save to the db, and the other to get info from the db), each from their own tab. I can get it all to work perfectly if I give the "get_users" controller action a view, but when I try to bring it back together on the same page, just in different tabs, it goes a little awry and I'm not sure how to route correctly.
The two controller actions I have are:
class Users::RegistrationsController < Devise::RegistrationsController
def user_accounts
#user = User.new
end
def get_users
#users = User.search(params[:search]).paginate
(:per_page => 20, :page => params[:page] )
end
end
EDIT ------------------------------------
Include routes.rb - excluding the extra devise related routes. Can get the create_internal_user action working not the other. I understand that the routes are
incorrect as rails could never understand them. The first is correct, the second is simply what I would imagine it to look like if it were possible
# Authentication
as :user do
#add new internal users
get '/useraccounts' => 'users/registrations#user_accounts', as: 'new_internal_user'
post '/useraccounts' => 'users/registrations#create_internal_user', as: 'internal_user'
**# searching users - this is where I am uncertain**
get '/useraccounts' => 'users/registrations#get_users', as: 'get_internal_user'
post '/useraccounts' => 'users/registrations#get_users', as: 'getting_internal_user'
# other devise routes here
end
The view that renders them looks like this and renders two partials:
<div class="container">
<h1>User Accounts</h1>
<ul class="nav nav-tabs">
<li class="active">Add User</li>
<li>Edit User</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane fade in active" id="adduser">
<%= render 'users/registrations/create_internal' %>
</div>
<div class="tab-pane fade in" id="getusers">
<%= render 'users/registrations/get_users' %>
</div>
</div>
</div>
The two partials
_create_internal.html.erb
<%= form_for(resource, as: resource_name,
url: new_internal_user_path(resource_name)) do |f| %>
<div><%= f.label :email %><br />
<% for role in User::ROLES %>
<%= check_box_tag "user[roles][#{role}]", role,
#user.roles.include?(role),
{:name => "user[roles][]"}%>
<%= label_tag "user_roles_#{role}", role.humanize %><br />
<% end %>
<%= hidden_field_tag "user[roles][]", "" %>
<div class="col-md-10 center"><%= f.submit "Create User",
class: "btn btn-primary"%></div>
<% end %>
_get_users.html.erb
<%= form_tag({:controller => "users/registrations", :action => "get_users"},
method: :get) do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
<div class="center" id="users">
<% if defined?(#users) %>
<%= render 'users/registrations/searchresults' %></div>
<%= will_paginate #users %>
<% end %>
I've spent many many hours trying to figure this out and just haven't been able to. Very new to Rails so this may be an easy question for someone. I've had a look at using AJAX, and resourceful routing, but as I'm still new I'm finding it a bit tough to wrap my head around it all at the one time. This is my first post on SO so apologies if I'm missing anything (please let me know).
Let's say your controller is UsersController and assuming your routes are not nested, this is how you create named routes:
get '/useraccounts', to: 'users#get_users' ## this route maps to the get_users action
post '/useraccounts' to: 'users#create_internal_user' # this route maps to the create_internal_user action
EDIT:
the format is controller_name#action_name. So make sure to replace users with your controllers name in plural
UPDATE:
if your controller's name is RegistrationsController
try:
get '/useraccounts', to: 'registrations#get_users'
post '/useraccounts' to: 'registrations#create_internal_user'
Looking at it, I think your error will likely be from your _get_users.html.erb partial.
Firstly, you're using form_for - why? Your use of form_for basically means you have to use the data inside #user to make it work, which I think will be causing the problem
I would use a form_tag as this does not persist your data:
<%= form_tag({:controller => "users/registrations", :action => "get_users"}, method: :get) do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
<% end %>
<% if defined?(#users) #-> this might need to be passed as a local var %>
<%= render 'users/registrations/searchresults' %></div>
<%= will_paginate #users %>
<% end %>
Routes
Your other problem is to do with your routes:
get '/useraccounts' => 'users/registrations#user_accounts', as: 'new_internal_user'
post '/useraccounts' => 'users/registrations#create_internal_user', as: 'internal_user'
**# searching users - this is where I am uncertain**
get '/useraccounts' => 'users/registrations#get_users', as: 'get_internal_user'
post '/useraccounts' => 'users/registrations#get_users', as: 'getting_internal_user'
Tell me how you expect Rails to know the difference between get '/useraccounts and get /useraccounts? The fact is it can't
You'll need to split up the routes so they don't all use the same path. I would do this:
get '/useraccounts' => 'users/registrations#user_accounts', as: 'new_internal_user'
post '/useraccounts' => 'users/registrations#create_internal_user', as: 'internal_user'
**# searching users - this is where I am uncertain**
get '/search' => 'users/registrations#get_users', as: 'get_internal_user'
After much frustration I have solved my own problem. With help from Rich Peck I realised that I was essentially creating a view with two forms on it, and that the tabbed navigation didn't really mean anything to the problem.
So I really only needed the two routes:
# #add new internal users
get '/useraccounts' => 'users/registrations#user_accounts', as: 'user_accounts'
post '/useraccounts' => 'users/registrations#create_internal_user', as:
'create_internal_user'
And then in the controller just changed the user_accounts action to look like this:
def user_accounts
#user = User.new
if params[:search_button]
#users = User.search(params[:search]).paginate(:per_page => 15, :page => params[:page] )
end
end
Came about this discovery thanks to this question/answer here:
form_for with multiple controller actions for submit
In the end the problem wasn't what I thought it was and ended up being simple. Was certainly an interesting learning journey. Thanks for your help again Rich Peck.
I keep getting an error saying: undefined method `androids_path' for #<#:0x007ff5edcd5330>. It's saying the error is at line 1 in new.html.
The name of the model is Android and is at android.rb. Any advice on how to fix this?
In androidapps_controller.rb:
def new
#android = Android.new
end
In new.html I have:
<%= form_for(#android, validate:true) do |f| %>
<% #android.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<%= f.submit %>
<% end %>
routes.rb
Grabapp::Application.routes.draw do
root :to => 'iosapps#index'
get "static_pages/home"
get "static_pages/add"
get "static_pages/about"
devise_for :users
resources :iosapps
resources :androidapps
Add to your routes.rb:
resources :android
You're error is because you've asked form_for to do resource based routing!
<%= form_for(#android, validate:true) do |f| %>
But you didn't define the resource based routing required to make it work!
Your model and controller are not matched (Android vs AndroidApp), so need to specify the correct url in your form:
<%= form_for(#android, validate: true, url: androidapps_path) do |f| %>
<%= form_for(#android, validate:true) do |f| %> automatically sets up the correct HTTP method (normally POST or PUT) with the HTML markup for a form. It also assumes you have a url set up called /androids in the case of POST and /androids/:id in the case of PUT. So for this to work you need to tell rails to create the necessary routings. This is done by adding the following line in config/routes.rb namely resources :androids.
This is why is is better to match up your model and controller names, Rails can then automatically infer the correct controller actions based on the model name.
You need to read up a bit more on routing and how it works. Do it here: http://guides.rubyonrails.org/routing.html
So I've been banging my head against the wall trying to figure out why this isn't working. I keep getting
ActionView::Template::Error:
undefined method `admin_information_index_path' for #<#<Class:0x007fc67971cab8>:0x007fc67d775740>
With the trace:
# ./app/views/admin/informations/_form.html.erb:1:in `_app_views_admin_informations__form_html_erb__2815737811953353352_70245242566200'
# ./app/views/admin/informations/new.html.erb:2:in `_app_views_admin_informations_new_html_erb___3700624853666844924_70245242606040'
Any tips in the right direction?
My routes:
namespace :admin do
resources :informations
end
My controller:
class Admin::InformationsController < Admin::AdminController
def new
#information = Information.new
end
end
views/admin/informations/new.html.erb:
<h1>Add New Information Page</h1>
<%= render :partial => 'form', locals: { information: #information } %>
views/admin/informations/_form.html.erb:
<%= form_for [:admin, information] do |f| %>
<%= error_messages_for information %>
<%= f.label :title %><br>
<%= f.text_field :title %><br><br>
<%= f.label :content %><br>
<%= f.text_area :content %><br><br>
<%= f.submit "Submit" %>
<% end %>
Output of rake routes
admin_informations GET /admin/informations(.:format) admin/informations#index
POST /admin/informations(.:format) admin/informations#create
new_admin_information GET /admin/informations/new(.:format) admin/informations#new
edit_admin_information GET /admin/informations/:id/edit(.:format) admin/informations#edit
admin_information GET /admin/informations/:id(.:format) admin/informations#show
PUT /admin/informations/:id(.:format) admin/informations#update
DELETE /admin/informations/:id(.:format) admin/informations#destroy
admin_root /admin(.:format) admin/sessions#new
Try just
<%= form_for information ,:namespace=>'admin' do |f| %>
UPDATE:
Look at your routes 'informations' pluralized, but your using the singular form 'information'
You must use correct form of controller, because:
'information'.pluralize
is
"information", not informations.
So, rename controller and view folder.
I'm not sure if this will work... Just a guess.
form_for #admin.information or something along those lines.