So, the set up is very simple. In my controller I have
class DriverController < ApplicationController
def index
end
def new
#driver = Driver.new
end
end
And the new.html.erb is
<h1>Driver#new</h1>
<%= form_for #driver do |f| %>
<%= f.submit %>
<% end %>
When I try to acess that new page it says: "undefined method `new' for Driver:Module"
When I change def new in my controller to def create for an example, this error goes away and it says that First argument in form cannot contain nil or be empty. What is the problem?
<h1>Driver#new</h1>
<%= form_for :driver, :url: drivers_path do |f| %>
<%= f.submit %>
<% end %>
In routes.rb
resourse :drivers
And further I would suggested you yo Visit Guide Ruby on Rails the-first-form
Hope this help you !!!
I don't know where the problem was, but I just did everything all over again, and it worked.
Related
I'm completely new to Rails. Just started from *http://guides.rubyonrails.org/getting_started.html
While trying I'm stuck with redirect_to problem like below error -
NoMethodError in SwversionsController#create
undefined method `sw_versions_url' for #<SwversionsController:0xa38d158>
Rails.root: C:/Sites/edisonprojectmanagement
Application Trace | Framework Trace | Full Trace
app/controllers/swversions_controller.rb:19:in `create'*
This error occurs after clicking submit button. I found the model is working fine and data is saved in my postgresql database.
I think problem is with my redirect_to method.
My SwVersionsController code looks like -
class SwversionsController < ApplicationController
def index
end
def show
#swversion = SwVersion.find(params[:id])
end
def new
end
def create
#swversion = SwVersion.new(swversion_params)
#swversion.save
redirect_to #swversion
end
private
def swversion_params
params.require(:swversion).permit(:sw_version, :description)
end
end
And the new.html.erb code is -
<h1> New SW versions </h1>
<%= form_for :swversion, url: swversions_path do |f| %>
<p>
<%= f.label :sw_version, "SW Version" %> <br>
<%= f.text_field :sw_version %>
</p>
<p>
<%= f.label :description, "Description" %> <br>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit "Submit" %>
</p>
<% end %>
My routes.rb is pretty simple
Rails.application.routes.draw do
resources :swversions
get 'welcome/index
Someone please help me to banish this problem
undefined method `sw_versions_url' for SwversionsController:0xa38d158
Naming Conventions:
Rails is very strict in naming and for a good reason. Rails expects the class names to be CamelCase and the methods/variables to be snake_case.
Your model class name is SwVersion, so the method/variable name should be sw_version not swversion. So you should change swversion to sw_version in your entire code
You should also change the controller class name to SwVersionsController.
And also if you have resources :swversions in routes.rb, then you should change it to resources :sw_versions
More about naming conventions here
Try this code:
redirect_to sw_version_path(#swversion)
I am pretty sure it's a very noob mistake, but I don't understand why I can't add my form directly to my homepage without causing a NoMethodError.
This is my current setup, and it works perfectly fine.
view/front_pages/home.html.erb (my home page)
<!--declare :title to be SHOULD I GET THIS-->
<% provide(:title, "SHOULD I GET THIS") %>
<div class = "container">
<h1>Should I really spend money on this?</h1>
<h2>Let's crunch in some numbers and find out...</h2>
<%= link_to "Get Started", calculate_path, class: "btn btn-info " %>
</div>
view/users/new.html.erb (where my form is right now)
<% provide(:title, "Calculate")%>
<div class = "form-group container">
<%= simple_form_for #user do |form|%>
<%= form.error_notification%>
<%= form.input :price%>
<%= form.input :wallet%>
<%= form.button :submit, "Submit", class: "submit"%>
<%end%>
</div>
controllers/users_controller.rb
class UsersController < ApplicationController
def new
#user = User.new
end
end
However, I want the form to be directly on my home page so the users don't need to click an extra button to get to the form. I tried
view/front_pages/home.html.erb
<!--declare :title to be SHOULD I GET THIS-->
<% provide(:title, "SHOULD I GET THIS") %>
<div class = "container">
<h1>Should I really spend money on this?</h1>
<h2>Let's crunch in some numbers and find out...</h2>
<%= link_to "Get Started", calculate_path, class: "btn btn-info " %>
</div>
<div class = "form-group container">
<%= simple_form_for #user do |form|%>
<%= form.error_notification%>
<%= form.input :price%>
<%= form.input :wallet%>
<%= form.button :submit, "Submit", class: "submit"%>
<%end%>
</div>
and it returns me the NoMethodError. I thought it's because I did not initiate a #user variable in the front_page controller, so I tried
class FrontPagesController < ApplicationController
def new
#user = User.new
end
def home
end
end
but it still does not work. I am thinking it's some concept about MVC that I still am not quite grasping. What is wrong with my code and what should I keep in mind next time so I don't make the same mistake?
PS: I use simple_form gem to generate my form
Edit: The error message is undefined method `model_name' for NilClass:Class
Error is quite simple:
Undefined method `model_name' for NilClass:Class
This error means you're trying to call the model_name method on a variable which is not populated with any data. You are not calling this method; form_for is - meaning you basically need to have #user declared in your controller, as you rightly pointed out:
class FrontPagesController < ApplicationController
def new
#user = User.new
end
def home
end
end
--
#user
The problem is that you're using the home action - you're declaring your #user variable in the new action. This means it won't be set, as it won't be called.
You'll be best doing this:
class FrontPagesController < ApplicationController
def home
#user = User.new
end
end
This will make #user available in your home action, which should resolve the error for you!
You need specify the action for the form
<%= form_for :user, url: { action: create } do |f| %>
or you can use your path helper if you have a resource defined for user
<%= form_for :user, url: user_path do |f| %>
I'm trying to get the Wicked Wizard gem working on my Rails app. Once a user registers for the app (using Devise), they're redirected to this form:
income.html.erb
<%= form_for #finance, url: wizard_path, :method => :put do |f| %>
<div class="field">
What <strong>year</strong> were you born?<br>
<%= f.number_field :age %>
</div>
<div class="field">
What's your <strong>zip code</strong>?<br>
<%= f.number_field :zip %>
</div>
<%= f.submit %>
<% end %>
I generated a controller called finances_welcome_controller.rb that handles wizard_path:
class FinancesWelcomeController < ApplicationController
before_filter :authenticate_user!
include Wicked::Wizard
steps :income, :expenses
def show
#finance = Finance.find_all_by_user_id current_user[:id] || #finance = current_user.finances.build(finance_params)
render_wizard
end
def update
#finance = Finance.find_all_by_user_id current_user[:id]
#finance.update(params[:finance])
render_wizard #finance
end
When I click the submit button, I'm getting this error:
NoMethodError in FinancesWelcomeController#update
undefined method `update' for #<Array:0x00000104c6ff48>
Extracted source (around line #14):
def update
#finance = Finance.find_all_by_user_id current_user[:id]
**#finance.update(params[:finance])**
render_wizard #finance
end
Not sure why the update method hasn't been defined since this is the same syntax that my resource's model is using. The Wicked Wizard gem was successfully implemented on this app.
a method starting find_all_by will return an array of Active record instances... not just a single one. update only works on a single instance.
So, either you want to run through all the instances in the array... using an each - or you want to just fetch the first one using find_by instead of find_all_by
In the case of finding by an id... I'd recommend changing it to find_by
so:
#finance = Finance.find_by_user_id current_user[:id]
#finance.update_attributes(params[:finance])
This is my code for rendering the partial (the #parties collection is being generated correctly, I have tested that):
<% #parties.each do |party| %>
<div class="item">
<%= render 'parties/party', :object => party %>
</div>
<% end %>
And this is the code in the partial:
<%= party.name %>
However, I get the following error:
undefined method `name' for nil:NilClass
I'm at my wits end, someone please help :-|
Also, this is the code for the controller to render the view containing the partial (The controller's called default_controller):
def index
#parties = Party.all
end
Is it of any consequence that this isn't the parties_controller?
I've tried something like below and it worked
<%= render :partial => 'party', :object => party %>
and I can access like party.name. the local variable is named after the partial name which is party here.
Note: Im assuming that your both partials are of parties_controller. So this should work.
Update:
Here is what ive tried with again
class PostsController < ApplicationController
#... ...
def index
#posts = Post.all
#comments = Comment.all #<---- Loading comments from PostsController
#... ...
end
end
#views/posts/index.html.erb
<% #comments.each do |comment| %>
<%= render :partial=>"comments/comment", :object=>comment %>
<% end %>
#views/comments/_comment.html.erb
<%= comment.body %>
And its working :)
My question is: why doesn't .becomes pass errors over to the new object? Isn't this the expected behaviour?
I have the following single table inheritance classes in a rails app:
class Document < ActiveRecord::Base
validates :title, :presence => true
end
class LegalDocument < Document
end
class MarketingDocument < Document
end
I want to use the same controller and set of views to edit both LegalDocuments and MarketingDocuments, so I am using DocumentsController < ApplicationController with the following edit and update actions:
def edit
#document = Document.find(params[:id])
end
def update
#document = Document.find(params[:id])
if #document.update_attributes(params[:document])
redirect_to documents_path, :notice => "#{t(:Document)} was successfully updated."
else
render :action => "edit"
end
end
and the following in my edit view:
<%= form_for #document.becomes(Document) do |f| %>
<% if f.object.errors.present? %>
<div class="error_message">
<h4><%= pluralize(f.object.errors.count, 'error') %> occurred</h4>
</div>
<% end %>
<div>
<%= f.label :title %>
<%= f.text_field :title, :class => "inputText" %>
</div>
<%= f.submit %>
<% end %>
If title is filled in, the documents update correctly.
If title is left blank, I am returned to the edit view BUT the error is not shown.
From debugging, I know it's not showing because f.object.errors is nil. However, from debugging, I also know #document.errors is NOT nil, as expected.
My question is: why doesn't .becomes pass errors over to the new object? Isn't this the expected behaviour?
Yes, I noticed that too.
Just change f.object.errors.present? by #document.errors.any? ( or #document.errors.present?).
If you really want to use f.object.errors.present?, write becomes in the controller (both edit and update actions) instead of in the view:
def edit
#document = Document.find(params[:id]).becomes(Document)
end
def update
#document = Document.find(params[:id]).becomes(Document)
# ....
end
And then in the view:
<%= form_for #document do |f| %>
<% if f.object.errors.present? %>
<p>Errrorsss....</p>
<% end %>
#.....
It happens because the url of the form is build according to #document.becomes(Document) (=> PUT document/:id) but #document is created according to its "true" class (a subclass of Document).
If you have pry (highly recommended), write:
def update
#document = Document.find(params[:id])
binding.pry
# ...
end
And then inspect #document. You will see that #document is an instance of LegalDocument or the other subclass even though you called #document.becomes(Document) in your form.
So in final f.object and #document are not the same.
This explains why you can't see f.object.errors when validation fails.
Edit
The 'best way' to deal with STI and form is NOT to use becomes:
<= form_for #document, url: { controller: 'documents', action: 'update' }, as: :document do |f| %>
<% if #document.errors.any? %>
# or if f.object.errors.any?
# handle validation errors
<% end %>
# your form...
<% end %>
This enables you:
to have only one controller (documents_controller)
to have only one resource (resources :documents)
it keeps trace of your subclasses: a LegalDocument will be store as a LegalDocument. No conversion: You don't have to store its class before the conversion to Document and then reassign it later.
Plus, your subclass is available in your form, so you can (let's imagine) build a select for the type.
your controller looks cleaner: #document = Document.find params[:id] nothing more. Just like a classic resource.
If you want to share this form across different actions(typically edit and new):
<%= form_for #document, url: { controller: 'media_files', action: action }, as: :media_file do |f| %>%>
# edit.html.erb
<%= render 'form', action: 'update' %>
# new.html.erb
<%= render 'form', action: 'create' %>
Pretty much it is a bug and it should work as you initially expected. The following patch to address the issue looks like it was pulled back in October
https://github.com/lazyatom/rails/commit/73cb0f98289923c8fa0287bf1cc8857664078d43