I am getting the following error when trying to use form_for in my Rails application:
undefined method `to_key' for #<Table::ActiveRecord_Relation:0x8a09ca8>
My config/routes.rb is:
root 'welcome#index'
post 'foo', as: 'foo', to: 'welcome#index'
The controller is:
class WelcomeController < ApplicationController
def index
#tables = Table.all
end
def test
#tables = Table.all
end
end
And the welcome/index.html.erb view is:
<p>
<%= form_for #tables, :url => foo_path do |t| %>
<%= t.text_area :name %>
<% end %>
</p>
I've tried to do the url workaround that had been suggested in the documentation, but I'm still getting the same error.
Does anyone know what I am doing wrong? I would like to understand this bug a bit more so I can better deal with it.
As per your code, index is returning a collection. However your view tries to define a form for it. This is unlikely going to be succeed.
Form is for an object, not for collections.
Perhaps you can do something like
def new
#table = Table.new
end
and in new.html.erb
<%= form_for #table do |f| %>
...
<% end %>
And if you would like to stick with index.html.erb with a form. Then you have to edit your routes for index action and also in controller it should be for creating a new object.
def index
#table = Table.new
end
Hope it helps!
I see your code have 3 not true things
As RESFUL standard then:
index action always go through with get action so in route file you should define again same that:
root "wellcome#index"
get "foo", to: "wellcome#index", as: :foo
form_for usually use with model object but not collect as you use #tables, if model object not save into database form_for using to create 1 object to database, otherwise form_for using update that object
if you want create form at index action you can follow me:
def index
#tables = Table.all
#table = Table.new
end
index.html.erb file
<%= form_for #table do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
you need create tables_controller to process request from form send to server. you run: rails g controller tables
In table_controller.rb you write same as:
def create
#table = Table.new table_params
if #table.save
redirect_to root_path, notice: "success"
else
redirect_to root_path, alert: "fail"
end
end
private
def table_params
params.require(:table).permit :name
end
so that. end. Have nice day!
Related
I'm working on messaging system between User and AdminUser. The User part is ready now I'm struggling how to allow Admin to send a reply to a conversation started by a User, inside of ActiveAdmin.
Code below:
# app/admin/conversations.rb
ActiveAdmin.register Conversation do
decorate_with ConversationDecorator
# ...
controller do
def show
super
#message = #conversation.messages.build
end
end
end
app/views/admin/conversations/_show.html.erb
# ...
<%= form_for [#conversation, #message] do |f| %>
<%= f.text_area :body %>
<%= f.text_field :messageable_id, value: current_user.id, type: "hidden" %>
<%= f.text_field :messageable_type, value: "#{current_user.class.name}", type: "hidden" %>
<%= f.submit "Send Reply" %>
<% end %>
<% end %>
Which gives me an error:
First argument in form cannot contain nil or be empty
Extracted source (around line #51):
51 <%= form_for [#conversation, #message] do |f| %>
When I tried to debug it turned out #message = nil inside of _show.html.erb. How is that possible if I defined #message inside of ActiveAdmin controller ?
[EDIT]
In case you're curious, ConversationController below:
class ConversationsController < ApplicationController
before_action :authenticate_user!
def index
#admins = AdminUser.all
#conversations = Conversation.all
end
def new
#conversation = Conversation.new
#conversation.messages.build
end
def create
#conversation = Conversation.create!(conversation_params)
redirect_to conversation_messages_path(#conversation)
end
end
#routes
resources :conversations do
resources :messages
end
Normally you set up instance variables in your controller, and then Rails later does an implicit render of the view once the controller method completes.
However, it is possible to do an explicit render of the view, by calling something like render action: or render template: while the controller method is running, and presumably this is happening within the call to super.
See the Layout and Rendering Rails Guide for more information.
You'll need to move the assignment to be before the call to super.
You may also need to replace #conversation with resource in the ActiveAdmin controller (this is an ActiveAdmin/InheritedResources gem thing).
Let say I want to create an additional create action. Let's call it create2.
items_controller:
def new
#item = Item.new
and
def create
.....
end
def create2
.....
end
items/form:
<%= simple_form_for (#item) do |f| %>
<%= f.input :name %>
<%= f.submit %>
<%= end %>
routes:
post 'create2', to: 'items#create2', as: :create2
Once I submit form, how can have it to execute create2 instead of create?
for example your model is User with users_controller and you want to create another "new-create"
inside your routes you add some thing like this
resources :users do
collection {
get :new_special_user
post :create_special_user
}
end
inside your users_controller you create 2 methods
def new_special_user
end
def create_special_user
end
inside new_special_user.html.erb, with url that will direct to create_special_user method in user contoller, below is the sample
<%= form_for #user, url: create_special_user_users_path do |f| %>
<% end %>
I have a little bit of a newbie question.
I have a basic form with a dropdown list that looks like the following :
## apply.html.erb
<%= form_for #category do |f| %>
<%= f.label 'parent' , 'Category' %>
<%= f.select :category, [["foo", 0 ], ["bar", 1 ]] %>
<% end %>
The dropdown list values are "foo" and "bar".
I am trying to pull values directly from a database. The problem is that I have no idea how to organize the controller and the model.
Here is the controller :
## Welcome_controller.rb
class WelcomeController < ApplicationController
def index
end
def apply
#category = 'foobar'
end
end
I have not generated the controller yet. I can not find any convincing answers to my question or tutorial on the internet.
Any idea how I can make it happen?
** EDIT **
So I have been doing some edits.Here is what I have:
The view
## apply.html.erb
<%= form_for #category, as: :category do |f| %>
<%= f.label 'Categories' %>
<%= f.select :category, #category %>
<% end %>
The controller :
## welcome_controller.rb
def apply
#category = Category.new
#categories = Category.pluck(:id, :name)
end
The model :
## Category.rb
class Category < ApplicationRecord
end
I get the following in the terminal :
ActionView::Template::Error (undefined method `categories_path' for #<#<Class:0x007ffb7c5a2808>:0x007ffb7c2814f8>):
3: <div id="category_block">
4: <span>What would you like to get financed ?</span>
5:
6: <%= form_for #category, as: :category do |f| %>
7: <%= f.label 'Categories' %>
8: <%= f.select :category, #category %>
9: <% end %>
app/views/welcome/apply.html.erb:6:in `_app_views_welcome_apply_html_erb___747255529581383389_70359048261520'
It looks like the problem comes from #category = Category.new because when I replace Category.new with a string like ' foobar', the error disappears.
Any idea how to fix this problem?
You should read more about the documentation. This is a pretty basic question, and you'll probably have the answer if you actually take the time to read and learn.
That said, the info you provided is lacking so I'll just assume.
First, I assume you have a Category model. It should be placed in app/models/category.rb:
def Category
...
end
Next, you're not actually querying anything from the database. You can do it this way:
## app/controllers/welcome_controller.rb
class WelcomeController < ApplicationController
def index
end
def apply
#category = Category.new
#categories = Category.pluck(:name, :id)
end
end
Category.new generates a new instance of the Category (category.rb) object.
Category.pluck(:name, :id) generates this array: [['foo', 1], ['bar', 2]], where name and id are attributes of the Category model (just change it to your liking).
Once you have your array stored in #categories, you can use it in your form like this:
## app/views/welcome/apply.html.erb
<%= form_for #category do |f| %>
<%= f.label 'parent' %>
<%= f.select :category, #categories %>
<% end %>
You're probably not planning to actually create a form for a Category considering that you have a dropdown for categories so you should just change it to something else. Also, take note of the file names. They're all lowercase and separated by underscores. (Welcome_controller.rb should be welcome_controller.rb)
** EDIT **
Now that you've added an object to the form_for, rails will automatically assign a path for your form unless you change it. For this case, the path is categories_path. Read more here.
What you need to do is modify your routes.rb and add the following line:
resources :categories
That line will automatically generate routes that provide a mapping between HTTP verbs and URLs to controller actions.
Next you need to create a CategoriesController:
## app/controllers/categories_controller.rb
class CategoriesController < ApplicationController
def create
#category = Category.new(category_params)
if #account_user.save
redirect_to apply_path
else
render :new
end
end
private
def category_params
params.require(:category).permit! # MODIFY THIS
end
end
Anyway, this is basically a walkthrough and you should be figuring this out yourself. There are a lot of resources out there -- it's not hard to find one. You can also check this out: video.
I have been having issues with form_for rendering. I want to have a _form.html.erb partial that deals with both the creation and editing of my Problem record. When I go down the route of using
<%= form_for(#problem) do |f| %>
I get the following error:
undefined method `model_name' for Problem::ActiveRecord_Relation:Class
In my routes.rb I have the following:
PW::Application.routes.draw do
root to: 'problems#index', via: :get
resources :problems do
member do
post 'up_vote'
post 'down_vote'
end
end
I also have this my in Problem Controller
class ProblemsController < ApplicationController
include Concerns::Votes
def new
#problem = Problem.new
end
def index
#problem = Problem.all
end
def show
#problem = find_problem
end
def create
#problem = current_user.problems.new(problem_params)
#problem.save
redirect_to #problem
end
private
def find_problem
#problem = Problem.find(params[:id])
end
def problem_params
params.require(:problem).permit(:name, :description, :url)
end
end
I can get it to work if I specify the following :
<%= form_for #problem.new, url: {action: "create"} do |f| %>
However I feel that this is repeating myself if I then have to make a separate partial just for the edit. I really cant work out why this doesn't want to work. Could it be I am rendering the form on index.html.erb?
Any help or direction would be very much appreciated.
LOL why didn't I see this earlier?
Could it be I am rendering the form on index.html.erb?
Yep, it's totally the problem. Reason is here:
Problem::ActiveRecord_Relation:Class
You're getting back a relation object (defines a collection, rather than single record). This is caused by this:
#controller
def index
#problem = Problem.all
end
The error is beacuse form_for expects a single record. You need to use this in your controller & it will work:
#controller
def index
#problem = Problem.new
#problems = Problem.all
end
#view
<%= #problems.each do |problem| %>
<%= problem.name %>
<% end %>
<%= form_for #problem do |f| %>
You might be using #problems, as you said the form is in index page. If you are doing so then the index action code should be like
def index
#problems = Problem.all
#problem = Problem.new
end
You should have a create method defined in your controller like this
def create
#problem = Problem.new
#other logic goes here
end
And your form_for for create action should be like this
<%= form_for #problem, url: {action: "create"} do |f| %>
I was getting a similar error:
undefined method `model_name' for form_for
It was for a simple reason:
I was using form_for, where I should have been using form_with. As soon as I changed that it worked as expected.
I have 2 models. Task and Location
Each task has_one location
task.rb
has_one :location
I am trying to create my controller for the Location model.
This is the new form
<%= form_for(#task.build_Location, :url => task_Location_path(#task)) do |f| %>
Fields
<%= f.submit %>
<% end %>
and the edit form
<%= form_for(#task.Location, :url => task_Location_path(#task)) do |f| %>
Fields
<%= f.submit %>
<% end %>
currently all functions operate properly with the exception of Update.
def create
#location = #task.create_Location(params[:location])
end
def update
#location = #task.locations.find(params[:id])
end
What is the proper way to define this method?
Not exactly sure what you are trying to do but...
you usually want to access #task via it's id; also, if a has_one, it wouldn't be pluralized.
If you were trying to update a task's name to 'something' you could do something like:
def update
#location=Location.find(params[:id])
#location.task.name="something"
#location.save
end
def update
#location = #task.location.update_attributes(params[:location])
end