Rails nested form throws undefined method for nilClass [closed] - ruby-on-rails

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed yesterday.
Improve this question
I am trying to build a nested form in Rails and run into an error when trying to render the form, with the form / view unable to find any of the models.
I have a Payment and Payment_ref models:
class Payment < ApplicationRecord
has_many :payment_refs
accepts_nested_attributes_for :payment_refs, allow_destroy: true, reject_if: :all_blank
end
class PaymentRef < ApplicationRecord
belongs_to :payment
end
PaymentRef has 1 string attribute: ref_note
I have an application helper from https://github.com/stevepolitodesign/rails-nested-form-example/blob/master/app/helpers/application_helper.rb (using this repo as a guide for my implementation), and then I have these partials / views:
# pay.erb.html:
<!-- a bunch of HTML -->
<%= render 'form' %>
# _form.erb.html:
<%= form_with model: #payment, local: true do |f| %>
<%= f.fields_for :payment_refs do |builder| %>
<%= render 'payment_ref', f: builder %>
<% end %>
<%= link_to_add_fields('Add Payment Ref', f, :payment_refs) %>
<% end %>
# _payment_ref.erb.html:
<%= f.label :ref_note %>
<%= f.text_field :ref_note %>
When I visit the pay view, I get
Showing /path/to/views/payments/_form.html.erb where line #5 raised:
undefined method `payment_refs' for nil:NilClass
Extracted source:
def link_to_add_fields(name, f, association, **args)
new_object = f.object.send(association).klass.new
The new_object line is highlighted as the source line throwing the error.
The view does not seem to be able to find the model through the helper. I have tried using payments as a parameter for the link_to_add_fields helper call (instead of payment_refs), and get the same error, but for payments being nil.
I am able to connect to rails console and create records:
#pref = PaymentRef.new
#pref.ref_code="Test Ref Code"
#pmnt = Payment.new
#pmnt.payment_refs.push(#pref)
#pmnt.payments_refs[0].ref_code
=> "Test Ref Code"
So i think the model is set up correctly - just unable to figure out why the model can't be found in the view.

Related

Associating two models together in Rails 4+

I have a User model which is working under Devise with no problems (using devise sanitizer to update fields, so no UsersController)
I am working on creating a Quiz model, which belongs_to the User model, and the User model has_one Quiz. In my routes, I have: resources :users, :quizzes (is this supposed to be quizzes or quizs? I know that Rails pluralizes but couldn't seem to find which it'd be in this case).
In my views, I'm trying to open up a modal (which works) and inside have it populated with fields that a User can enter in questions they want (q1 through q5 being the database fields).
Inside the modal content area, I have the code:
<%= form_for #quiz, url: {action: "new"} do |f| %>
<%= f.submit "Create" %>
<% end %>
and I get the error "First argument in form cannot contain nil or be empty"
Inside my quizzes controller, I have defined new as
def new
#quiz = Quiz.new
end
I would greatly appreciate some assistance here! Thank you.
In your WelcomeController action: index add this line to initialized #quiz
def index
#quiz = Quiz.new
end
hope you made a good progress in your project.
shoudn't it be like following
<%= form_for #quiz do |f| %>
<%= f.submit "Create" %>
<% end %>

Rails: Create Model and join table at the same time, has_many through

I have three Models:
class Question < ActiveRecord::Base
has_many :factor_questions
has_many :bigfivefactors, through: :factor_questions
accepts_nested_attributes_for :factor_questions
accepts_nested_attributes_for :bigfivefactors
end
class Bigfivefactor < ActiveRecord::Base
has_many :factor_questions
has_many :questions, through: :factor_questions
end
and my join-table, which holds not only the bigfivefactor_id and question_id but another integer-colum value.
class FactorQuestion < ActiveRecord::Base
belongs_to :bigfivefactor
belongs_to :question
end
Creating an new Question works fine, using in my _form.html.erb
<%= form_for(#question) do |f| %>
<div class="field">
<%= f.label :questiontext %><br>
<%= f.text_field :questiontext %>
</div>
<%= f.collection_check_boxes :bigfivefactor_ids, Bigfivefactor.all, :id, :name do |cb| %>
<p><%= cb.check_box + cb.text %></p>
<% end %>
This let's me check or uncheck as many bigfivefactors as i want.
But, as i mentioned before, the join model also holds a value.
Question:
How can I add a text-field next to each check-box to add/edit the 'value' on the fly?
For better understanding, i added an image
In the console, i was able to basically do this:
q= Question.create(questiontext: "A new Question")
b5 = Bigfivefactor.create(name: "Neuroticism")
q.bigfivefactors << FactorQuestion.create(question: q, bigfivefactor: b5, value: 10)
I also found out to edit my questions_controller:
def new
#question = Question.new
#question.factor_questions.build
end
But i have no idea how to put that into my view.
Thank you so much for your help!
Big Five Factors model considerations
It looks like your Bigfivefactors are not supposed to be modified with each update to question. I'm actually assuming these will be CMS controlled fields (such that an admin defines them). If that is the case, remove the accepts_nested_attributes for the bigfivefactors in the questions model. This is going to allow param injection that will change the behavior sitewide. You want to be able to link to the existing bigfivefactors, so #question.factor_questions.first.bigfivefactor.name is the label and #question.factor_questions.first.value is the value. Notice, these exist on different 'planes' of the object model, so there wont be much magic we can do here.
Parameters
In order to pass the nested attributes that you are looking for the paramater needs to look like this:
params = {
question: {
questiontext: "What is the average air speed velocity of a sparrow?",
factor_questions_attributes: [
{ bigfivefactor_id: 1, value: 10 },
{ bigfivefactor_id: 2, value: 5 } ]
}
}
Once we have paramaters that look like that, running Question.create(params[:question]) will create the Question and the associated #question.factor_questions. In order to create paramaters like that, we need html form checkbox element with a name "question[factor_questions_attributes][0][bigfivefactor_id]" and a value of "1", then a text box with a name of "question[factor_question_attributes][0][value]"
Api: nested_attributes_for has_many
View
Here's a stab at the view you need using fields_for to build the nested attributes through the fields for helper.
<%= f.fields_for :factor_questions do |factors| %>
<%= factors.collection_check_boxes( :bigfivefactor_id, Bigfivefactor.all, :id, :name) do |cb| %>
<p><%= cb.check_box + cb.text %><%= factors.text_field :value %></p>
<% end %>
<% end %>
API: fields_for
I'm not sure exactly how it all comes together in the view. You may not be able to use the built in helpers. You may need to create your own collection helper. #question.factor_questions. Like:
<%= f.fields_for :factor_questions do |factors| %>
<%= factors.check_box :_destroy, {checked => factors.object.persisted?}, '0','1' %> # display all existing checked boxes in form
<%= factors.label :_destroy, factors.object.bigfivefactor.name %>
<%= factors.text_box :value %>
<%= (Bigfivefactor.all - #question.bigfivefactors).each do |bff| %>
<%= factors.check_box bff.id + bff.name %><%= factors.text_field :value %></p> # add check boxes that aren't currently checked
<% end %>
<% end %>
I honestly know that this isn't functional as is. I hope the insight about the paramters help, but without access to an actual rails console, I doubt I can create code that accomplishes what you are looking for. Here's a helpful link: Site point does Complex nested queries

Rails 4 error: can't write unknown attribute `html'

Running into an error trying to set up a basic Rails 4 app for learning purposes, so bear with me! I am trying to create an app to create and display custom web forms. I have a Form model, which has many Fields. I'm at the point where I'm trying to get the view working that will allow me to create a new Field record attached to a specific Form:
class Form < ActiveRecord::Base
has_many :fields
end
class Field < ActiveRecord::Base
belongs_to :form
end
On my Field index view, which I believe I have set up to correctly to only show the Fields of a specific form (via a url like /forms/1/fields), I have a link as such:
<%= link_to 'New Field', new_form_field_path(#form) %>
The fields/new.html.erb file has this:
<h1>New field</h1>
<%= render :partial => 'form', :form => #form, :field => #field %>
And the fields/_form.html.erb starts like this:
<%= form_for(#form, #field) do |f| %>
The fields_controller.rb has this method defined:
def new
#form = Form.find(params[:form_id]) #unsure if this is necessary/correct, but its presence doesn't effect the error i'm getting
#field = Field.new
end
A Form with id 1 has already been created. It looks like /forms/1/fields comes up ok. But when I click the "New Field" link, which takes me to /forms/1/fields/new, I get this error:
Showing /home/moskie/Projects/FormBuilder/app/views/fields/_form.html.erb where line #1 raised:
can't write unknown attribute `html'
Extracted source (around line #1):
<%= form_for(#form, #field) do |f| %>
<% if #field.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#field.errors.count, "error") %> prohibited this field from being saved:</h2>
Trace of template inclusion: app/views/fields/new.html.erb
Rails.root: /home/moskie/Projects/FormBuilder
Application Trace | Framework Trace | Full Trace
app/views/fields/_form.html.erb:1:in `_app_views_fields__form_html_erb___1866877160086017450_70350628427620'
app/views/fields/new.html.erb:3:in `_app_views_fields_new_html_erb___1515443138224133845_70350627074400'
Request
Parameters:
{"form_id"=>"1"}
I'm pretty confused by what this error is telling me, so I'm having trouble figuring out what I've done wrong here. Can anyone help me out? Thanks.
Got it. The call to form_for in the _form.html.erb Field partial view needed square brackets, instead of the parenthesis. The method wants an array of the two objects as its first parameter in this case, not to have the two objects passed in separately:
<%= form_for [#form, #field] do |f| %>

Trouble using Simple Form on a rails starter project

I'm getting the following error while trying to create a form, undefined method 'model_name' for NilClass:Class
This project of mine is to capture my ideas. I could use a google doc but figured this should be easy enough to try and code an app for myself. Below is the code as I think it should be from what I read on the simple form site in my newopp.html.erb (in my opps view folder.
I created a controller and a model and I am certain part of my problem is the fact that I can't figure out what I need to code or what to add for code to properly complete this step. All the tutorials I have looked at gave me a couple ideas to play with and try to make work to no avail.
So basically I am sitting on a rails generated controller named opps_controller.rb and a model called opp.rb. Both of these are nothing more than what the generator provided since I had to go back to square one
Simple form code that I have started with
<%= simple_form_for #opp do |f| %>
<%= f.input :title %>
<%= f.input :subtitle %>
<%= f.input :description %>
<%= f.input :idea %>
<%= f.input :added %>
<%= f.button :submit %>
<% end %>
opp.rb file
class Opp < ActiveRecord::Base
attr_accessible :added, :description, :idea, :subtitle, :title
end
If it makes a difference, I have migrated the database, I ran the simple form install script with the bootstrap configuration. I'm using rails 3.2.9 and ruby 1.9.3p362 (2012-12-25 revision 38607) [x86_64-darwin12.2.1]
As I mentioned I just have a blank controller that was created using a generator and I need to get the CRUD functionality working. Everything I have tried has failed at this point. I appreciate any assistance you can provide.
It shouldn't be newopp.html.erb, just new.html.erb. So the path would be /views/opps/new.html.erb
If you're still getting an error then make sure #opp is defined in the controller:
class OppsController < ApplicationController
def new
#opp = Opp.new
end
def create
#opp = Opp.new
if #opp.update_attributes(params[:opp])
...
else
render 'new'
end
end
end

Rails - nested forms to link has_one's where the child object has already been created

I have two models which are linked in a has_one / belongs_to association; Computer and Ipv6Address respectively.
I have pre-populated the Ipv6 table with all the entries that I want it to have, and I now need to have a drop-down list on the Computer new/edit forms to select an item from Ipv6 to associate it with.
Everything I've seen so far on this only seems to work when you are creating both objects at the same time on the new form and then subsequently editing them.
I've tried to set up my MVC's as per the examples I've found online, but I keep getting errors, as underneath these code excerpts:
Computer model:
class Computer < ActiveRecord::Base
accepts_nested_attributes_for :ipv6_address
has_one :ipv6_address
...
Ipv6Address model:
class Ipv6Address < ActiveRecord::Base
attr_accessible :computer_id, :ip_address
belongs_to :computer
...
Computer controller:
class ComputersController < ApplicationController
def new
#computer = Computer.new
#ipv6s = Ipv6Address.where('computer_id IS NULL').limit(5)
end
def edit
#computer = Computer.find(params[:id])
#ipv6s = Ipv6Address.where('computer_id = #{#computer.id} OR computer_id IS NULL').order('computer_id DESC').limit(5)
end
Computer new form:
<%= simple_form_for( #computer ) do |f| %>
<%= f.fields_for :ipv6_addresses do |v6| %>
<%= v6.input :ipv6_address, :collection => #ipv6s %>
<% end %>
<% f.button :submit %>
<% end %>
Error when browsing to computer new form:
NoMethodError in ComputersController#new
private method `key?' called for nil:NilClass
No line of code reference is given for this error, but it only appears when I have the nested form included in the computer new form.
Any ideas as to what is causing it or how I can better go about what I'm doing?
EDIT:
As it turns out, I needed to have accepts_nested_attributes_for :ipv6_address after the line has_one :ipv6_address in the Computer model.
That fixed the issue with the form loading.
As per Yarden's answer, I then also singularized all instances of "ipv6_address" so as to reflect the has_one relationship.
Once doing that in the new form, however, the ipv6 field completely disappeared. I'll open a new question with this one if I can't get it sorted out shortly.
Try adding ':', I think that may be the problem :
<%= f.fields_for :ipv6_addresses do |v6| %>
Also you forgot to add a '.' here:
#ipv6s = Ipv6Address.where('computer_id IS NULL').limit(5)
Edit after change:
The problem is that its only a has_one relationship so it doesnt know the plural of :ipv6_address as you stated in your model... you need to change it to :ipv6_address instead of :ipv6_addresses...
Also in your form change the :ipv6_address to the actual field which is :ip_address.
So overall your form should look like this:
<%= simple_form_for( #computer ) do |f| %>
<%= f.fields_for :ipv6_address do |v6| %>
<%= v6.input :ip_address, :collection => #ipv6s %>
<% end %>
<% f.button :submit %>
<% end %>

Resources