Rails 4 error: can't write unknown attribute `html' - ruby-on-rails

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| %>

Related

Why is my nested resource form trying to use a non-existent path method when I've already set the URL?

I have the following routes defined in my application:
resources :users do
resources :data_sets
end
The form data_sets/new is accessed from the following link:
<%= link_to "New Data Set", new_user_data_set_path(user) %>
The form is defined as such:
<%= form_with model: #data_set, url: [#data_set.author, #data_set] do |form| %>
<!-- form contents... -->
<% end %>
The form gives the following error upon loading:
Showing .../app/views/data_sets/new.html.erb where line #1 raised:
undefined method `data_sets_path' for #<#<Class:0x00007ffd2d1dcf90>:0x00007ffd292a63d0>
The following parameters were passed:
{ "user_id" => "1" }
Similar questions posted here seem to indicate that defining the URL typically solves problems with nested resource forms, but as you can see I already have. What else is going on here?
The form_with helper build the nested url from the array you passed. But in case of new record, #data_set.author returns nil and the form tries to reach data_sets_path which does not exist.
If your form is just for the "new" action you can write:
<%= form_with model: #data_set, url: [:user, #data_set] do |form| %>
If you share the form between "new" and "edit", you can write a condition like that:
<%= form_with model: #data_set, url: [(#data_set.new_record? ? :user : #data_set.author), #data_set] do |form| %>

undefined variable 'f' when rendering portions of a form through ajax

I have a situation where a Contact has many Leads and a Lead belongs to Profile polymorphically. I successfully rendered the form as such:
# _form.html.erb
<%= form_for #lead do |f| %>
<%= f.fields_for :contact do |builder| %>
<%= render "contact_fields", :f => builder %>
<%= render "leads_field", f: f %>
<% end %>
<% end %>
# lead_field.html.erb
<%= f.select :practice_type, PRACTICE_TYPES.collect {|type| [ type, type ] }
<%= f.fields_for :practice do |builder| %>
<%= render "#{#practice.class.name.underscore}_field", :f => builder %>
<% end %>
The above works fine with page load. However, a user can select a practice from dropdown menu and then I send ajax request to repopulate the form building an association with that practice:
$('#lead_practice_type').change(function() {
$.ajax({
url: "/leads/new",
data: {
profile_type : $(this).val()
},
dataType: "script"
});
});
The error occurs in new.js.erb:
$("#form_holder").html("<%= escape_javascript(render(:partial => "leads_field"))%>");
I want to only render that partial (if I render whole form, then all their contact information would be erased.). But because that partial contains a local f variable, it blows up:
NameError - undefined local variable or method `f'
I want to maintain the relations between the objects but also update just that one partial. But it appears I cannot do it through the new.js.erb script because when it renders the partial, there is no local variable 'f' passed.
Is there another alternative to achieve what I want?
I found this problem difficult to solve on two fronts. First, There is no way you can identify the form builder from the controller action and javascript. Second, although I am quite familiar with the railscasts episode http://railscasts.com/episodes/196-nested-model-form-revised?view=comments, in that episode he knew the fields_for to generate at compile time, and therefore he hid the markup in the data field of a link. Unfortunately, in my case I would not know the fields_for the user wants until runtime (when the browser loads and user selects an option).
I also realized that fields_for is important to maintain nice associations for form submission so that the create action would be simply: save the parent resource and it saves its associations.
The best solution I could come up with is as follows.
1) Create ALL the polymorphic associations with fields_for and hide the ones the user doesn't want via a select form field:
# template
<div id="runtime-profile">
<% Lead::TYPES.each_with_index do |association, index| %>
<div id="profile_<%= association %>">
<fieldset class="field-border">
<legend class="field-border"><%= association.underscore %></legend>
<%= f.fields_for :practice, build_builder_association(f, association) do |builder| %>
<%= render "#{builder.object.class.name.underscore}_field", :f => builder %>
<% end %>
</div>
<% end %>
</div>
# helper
def build_builder_association(f, association)
f.object.practice_type = association
f.object.build_practice({})
end
Use Javascript to hide and show the templates based on an option selected from dropdown, and then when form is submitted, remove the hidden elements from the DOM:
$("#new_lead").submit(function(){
$("[id^='profile_']:hidden").remove();
})
And that creates the original desired behavior I wanted. However, the solution is far from clean and any better suggestions are welcome.

Rails form for mailing

I'm trying to build a form which preloads content from two models (two variables being passed, being shown in the textfields) and then, not saves the data but sends the altered content (from the textfields) as two(?) variables to a mailer class.
I've managed to preload the data from one of the two models but am not sure how the form_for tag has to look like to get both models loaded as well as targeting the mailer class method instead of updating the model entity when pressing "send".
Do I need the accepts_nested_attributes_for attribute inside the model if I'm not saving anything?
I hope someone could give me an small example of the crucial parts. A thousand thanks!
You can use fields_for to include other models in same form. You can use it inside the same form_for what is present.
Checkout the example here from the api docs,
<%= form_for #person do |person_form| %>
First name: <%= person_form.text_field :first_name %>
Last name : <%= person_form.text_field :last_name %>
<%= fields_for #person.permission do |permission_fields| %>
Admin? : <%= permission_fields.check_box :admin %>
<% end %>
<%= f.submit %>
<% end %>
when you submit the data from this form, you can just use that data to pass to the mailer class from controller. UserMailer.get_user_info(params[:name], params[:address]).send
Creates a scope around a specific model object like #form_for, but doesn't create the form tags themselves. This makes #fields_for suitable for specifying additional model objects in the same form.
Refer Docs here:.
fields_for(record_name, record_object = nil, options = {}, &block)

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

How to access nested child element in fields_for

I'm trying to access a Hash type of mongoid in fieds_for and I already have a relationship with a model and want to access a hash of that model. Something like:
class Leave
field :leaves_types, :type => Hash
end
class User
has_many :leaves
end
Want to do something like:
form_for #user do |f|
f.fields_for :leaves.leave_types...
How I can achieve this? Thanks in advance.
You should give a block to fields_for. For more information on that method see docs. In your case, first, add this line to your User model:
class User
has_many :leaves
accepts_nested_attributes_for :leaves
end
This is required so that when your form is posted, the attributes coming from the form fields for leaves via params were handled correctly.
Now your template should look like this (for simplicity by now I assume that your Leave also has a simple text field named foo):
<%= form_for #user do |f| %>
...
<%= f.fields_for :leaves do |leave_fields| %>
# Fields for a leave here ----v
Foo: <%= leaves_fields.text_field :foo %>
<% end %>
<% end %>
Or, if you #user.leaves already initialized and you want form builder to put its values to form fields, you have to iterate over #user.leaves, passing each of them to fields_for as second argument:
<%= form_for #user do |f| %>
...
<% #user.leaves.each do |leave| %>
<%= f.fields_for :leaves, leave do |leave_fields| %>
# Note the addition here --^
Foo: <%= leave_fields.text_field :foo %>
<% end %>
<% end %>
<% end %>
But your question has another one inside: you have not a text field, but a hash, and there is no default form input for it (i.e. there is no f.hash_field :leaves_types). So you may want to make it by yourself like suggested in these questions: [1], [2] and [3].
Anyway, having a Hash field seems rather uncommon to me, so maybe Hash can be somehow replaced, say, with another has_many association (not sure), and in this case you will only need another nested fields_for.

Resources