Does accepts_nested_attributes_for work with belongs_to? - ruby-on-rails-3

I have been getting all kinds of conflicting information regarding this basic question, and the answer is pretty crucial to my current problems. So, very simply, in Rails 3, is it allowed or not allowed to use accepts_nested_attributes_for with a belongs_to relationship?
class User < ActiveRecord::Base
belongs_to :organization
accepts_nested_attributes_for :organization
end
class Organization < ActiveRecord::Base
has_many :users
end
In a view:
= form_for #user do |f|
f.label :name, "Name"
f.input :name
= f.fields_for :organization do |o|
o.label :city, "City"
o.input :city
f.submit "Submit"

Nested attributes appear to work fine for a belongs_to association as of Rails 4. It might have been changed in an earlier version of Rails, but I tested in 4.0.4 and it definitely works as expected.

The doc epochwolf cited states in the first line "Nested attributes allow you to save attributes on associated records through the parent." (my emphasis).
You might be interested in this other SO question which is along the same lines as this one. It describes two possible solutions: 1) moving the accepts_nested_attributes to the other side of the relationship (in this case, Organization), or 2) using the build method to build the Organization in the User before rendering the form.
I also found a gist that describes a potential solution for using accepts_nested_attributes with a belongs_to relationship if you're willing to deal with a little extra code. This uses the build method as well.

For belongs_to association in Rails 3.2, nested model needs the following two steps:
(1) Add new attr_accessible to your child-model (User model).
accepts_nested_attributes_for :organization
attr_accessible :organization_attributes
(2) Add #user.build_organization to your child-controller (User controller) in order to create column organization.
def new
#user = User.new
#user.build_organization
end

For Ruby on Rails 5.2.1
class User < ActiveRecord::Base
belongs_to :organization
accepts_nested_attributes_for :organization
end
class Organization < ActiveRecord::Base
has_many :users
end
Just got to your controller, suppose to be "users_controller.rb":
Class UsersController < ApplicationController
def new
#user = User.new
#user.build_organization
end
end
And the view just as Nick did:
= form_for #user do |f|
f.label :name, "Name"
f.input :name
= f.fields_for :organization do |o|
o.label :city, "City"
o.input :city
f.submit "Submit"
At end we see that #user3551164 have already solved, but now (Ruby on Rails 5.2.1) we don't need the attr_accessible :organization_attributes

Related

How to create new records with nested attributes in a ruby on rails "has many through" relationship?

I need some advice on building a has many through relationship between USER, THING and EXTRA models.
My USER model is slightly modified inside Devise gem and is noted as Creator whereas other models belonging to USER receive :created_things form.
In my app, USERS create THINGS can later add EXTRAS to their THINGS.
I chose has many through because I want to have unique data on all three models and be able to call both THINGS and EXTRAS from the USER "CREATOR" model.
I have built this many different ways and after 10 years of solving my problems by reading stackoverflow, I am finally submitting this request for support! Thank you for your help.
I have tried creating user and extra references on the THING model and declaring nested attributes in the USER and THING model. I have tried several examples from stackoverflow inside the create and new methods but nothing seems to work.
class User < ApplicationRecord
has_many :created_things, class_name: Thing, foreign_key:
:creator_id, :dependent => :destroy
has_many :extras, through: :created_things
accepts_nested_attributes_for :extras, :reject_if => :all_blank,
allow_destroy: true
class Thing < ApplicationRecord
belongs_to :creator, class_name: User
has_many :extras
accepts_nested_attributes_for :extras, :reject_if => :all_blank,
allow_destroy: true
class Extra < ApplicationRecord
belongs_to :creator, class_name: User, inverse_of: :thing
belongs_to :created_things
Members Index.html.erb
<% if thing.extras.exists? %>
<% thing.extras.each do |extra| %>
<%= extra.title %> <%= link_to "[+]", edit_extra_path(extra) %>
<% end %>
<% else if thing.extras.empty? %>
<%= link_to "+1 EXTRA", new_extra_path(current_user) %>
<% end %>
<% end %>
class MembersController < ApplicationController
before_action :authenticate_user!
def index
#user = current_user
#created_extras = #user.extras
#created_things = #user.created_things
end
class ExtrasController < ApplicationController
def new
#extra = Extra.new
end
def create
#extra = current_user.extras.build(extra_params)
if #extra.save
I am able to create a new EXTRA but the :thing_id remains nul as it does not display when called on the show extra view. Therefore I am not surprised that when I return to the member index page that my thing.extras.exists? call is returning false and the created extra never displays under the THING view. My attempts to modify the extra controller have failed and I some of my reading sugested the extras controller is not necessary in this relationship so I am really at a loss on how this is built. I'm assuming I am missing something in new and create methods maybe in things or user controller? Perhaps I'm missing something in routes resources? Any advice is greatly appreciated. Thank you.
Ok, I figured it out. I really didn't need has many through for this model and I did a lot of testing of the syntax on each model.rb and in the end was able to figure it out from this stackoverflow . . .
[Passing parent model's id to child's new and create action on rails
Here are my the various parts of setting up a has many and belongs to relationship with nested attributes.
class Thing < ApplicationRecord
belongs_to :creator, class_name: User
has_many :extras, inverse_of: :thing, :dependent => :destroy
accepts_nested_attributes_for :extras, allow_destroy: true
class Extra < ApplicationRecord
belongs_to :thing, inverse_of: :extras
extras_controller.rb
class ExtrasController < ApplicationController
def new
#extra = Extra.new(thing_id: params[:thing_id])
end
def create
#user = current_user
#extra = Extra.new(extra_params)
#extra.user_id = #user.id
if #extra.save
flash[:success] = "You have added a new Extra!"
redirect_to #extra #extras_path later
else
flash[:danger] = "The form contains errors"
render :new
end
end
edit.html.erb things
<% if #thing.extras.exists? %>
<p>current extras associated with <%= #thing.title %>: </p>
<% #thing.extras.each do |extra| %>
<p><%= extra.title %> <%= link_to "[+]", edit_extra_path(extra) %>
/ <%= link_to "[-]", extra_path(extra), method: :delete %> </p>
<% end %>
<% end %>
<%= link_to "+1 EXTRA", new_extra_path(thing_id: #thing.id) %>
<%= render 'things/form' %>

Find_or_initializes_by for a complex model

Newbie Rails user here so sorry if I'm totally overlooking something; I'm just looking for direction on what resources I should use to solve this problem.
I have a Rails app running that uses virtual attributes to define a complicated has_many :through relationship. What I'm looking to do is to use the id of an existing entry rather than creating a new one when a user submits a form. I have attempted to use find_or_initializes_by and find_or_create to no avail. Depending on how I set it up, it either changes one of the diagnosis columns on the join table successfully (but leaves the other diagnosis column blank, causing a rollback), or it doesn't work at all.
Background for my use case: a Case can have many diagnoses (Diagnosis), some of which are primary, and others are "differential" diagnoses. Cases and multiple diagnoses are related in a join table.
My current setup:
case.rb
def new
#case = Case.new
#case_and_diagnoses = #case.case_and_diagnoses.build
#primary_diagnoses = #case_and_diagnoses.build_primary_diagnosis
#differential_diagnoses = #case_and_diagnoses.build_differential_diagnosis
end
The relevant section of the case form:
<%= f.fields_for :case_and_diagnoses do |x| %>
<%= x.fields_for :primary_diagnosis do |diagnosis| %>
<%= diagnosis.label :name, "Diagnosis" %>
<%= diagnosis.text_field :name %>
<% end %>
<%= x.fields_for :differential_diagnosis do |differential| %>
<%= differential.label :name, 'Differential diagnosis' %>
<%= differential.text_field :name %>
<% end %>
<% end %>
What's the best way to tackle this problem? I don't need an explicit code block to use, but I'm looking for a strategy so I can maybe find my own way. Thank you very much!
Update:
The models:
class Case < ApplicationRecord
before_save :get_diagnoses
belongs_to :submitter, class_name: 'User', foreign_key: 'submitter_id'
belongs_to :resident, class_name: 'User', foreign_key: 'resident_id'
belongs_to :faculty, class_name: 'User', foreign_key: 'faculty_id'
has_one :service
has_many :case_and_diagnoses
has_many :primary_diagnoses, through: :case_and_diagnoses
has_many :differential_diagnoses, through: :case_and_diagnoses
accepts_nested_attributes_for :case_and_diagnoses
end
class Diagnosis < ApplicationRecord
has_many :case_and_diagnoses
has_many :cases, through: :case_and_diagnoses
end
class CaseAndDiagnosis < ApplicationRecord
belongs_to :case
belongs_to :primary_diagnosis, class_name: 'Diagnosis', foreign_key: :primary_diagnosis_id, optional: true
belongs_to :differential_diagnosis, class_name: 'Diagnosis', foreign_key: :differential_diagnosis_id, optional: true
accepts_nested_attributes_for :primary_diagnosis, :differential_diagnosis
end

How to use "accepts_nested_attributes_for" in rails 3?

I'm following the docs and toying with simple_form, formtastic, and nested_form gems with no success. This very simple example yields empty for for me:
resort.rb
class Resort < ActiveRecord::Base
attr_accessible :address, :description, :latitude, :longitude, :name, :phone, :second_name,
:resort_type_id, :infrastructure_attributes
validates_presence_of :name, :address, :phone, :description
has_many :infrastructures
belongs_to :resort_type
accepts_nested_attributes_for :infrastructures
end
infrastructure.rb
class Infrastructure < ActiveRecord::Base
attr_accessible :name, :description, :infrastructure_type_id, :resort_id
belongs_to :resort
belongs_to :infrastructure_type
end
form view
= form_for #resort do |f|
= f.fields_for :infrastructures do |i|
= i.text_field :name
Seems I missed something obvious but can't figure out what exactly is wrong with the code.
If I may ask, in your controller action did you build the appropriate code for your infrastructure. Something like
3.times { #resort = #resort.infrastrucures.build }
To my knowledge you need something like this for your form before it can build the proper nested form content

Added two "belongs_to" to a Comment model but unable to get one of the associations

I am currently building very simple Comment system on Rails. The primary models are User, Albumpost, and Comment. Users can post Albumposts. For each Albumpost, Users can add Comments to the Albumpost. As a result, a Comment belongs to a User and belongs to an Albumpost.
The problem I'm having is that even with the proper associations in my models (see below), I can't get
#comment.user.name
when I'm trying to render the comments in the albumpost 'show' page (/views/albumposts/show.html.erb). When I go to the page, I can't get #comment.user.name (doesn't understand the association) and get a
"undefined method `name' for nil:NilClass"
Oddly I can get
#comment.albumpost.content
I've double-checked my models and also added the proper foreign keys to the models. Am I doing something wrong in the controllers?
Here are my models:
class Comment < ActiveRecord::Base
attr_accessible :body, :albumpost_id, :user_id
belongs_to :albumpost
belongs_to :user
end
class Albumpost < ActiveRecord::Base
attr_accessible :content
belongs_to :user
has_many :comments, dependent: :destroy
end
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_many :albumposts, dependent: :destroy
has_many :comments, dependent: :destroy
end
Here are the relevant parts of my Albumpost and Comments controllers:
class AlbumpostsController < ApplicationController
def show
#albumpost = Albumpost.find(params[:id])
#comments = #albumpost.comments
#comment = Comment.new
#comment.albumpost_id = #albumpost.id
#comment.user_id = current_user.id
end
end
class CommentsController < ApplicationController
def create
albumpost_id = params[:comment].delete(:albumpost_id)
#comment = Comment.new(params[:comment])
#comment.albumpost_id = albumpost_id
#comment.user_id = current_user.id
#comment.save
redirect_to albumpost_path(#comment.albumpost)
end
end
I think you should prefer setting objects to relations instead of setting their ids. For example, you should do this:
#comment.user = current_user
instead of
#comment.user_id = current_user.id
ActiveRecord will take care of setting corresponding *_id fields. I'm not sure how it handles the reverse. (it should autoload though, if I understand correctly)

Rails, get object association when using build (object still not in database), the DRY

Im building a report system which uses a sort of meta question model. Questions are previusly saved in the database, and then depending of the type of report some questions are taken from the database.
Wanting to keep things DRY, i'm trying to figure out a way to pass the information of the Variable model to my report_header with no avail.
In the new action i have:
reportBody = #report_head.report_bodies.build(:variable_id => a.id)
#report_head.variables #modified, thx.
all i need is to pass the attributes from the Variable to report_head in a DRY way.
If you need to know my models:
class Variable < ActiveRecord::Base
attr_accessible :id,:break_point, :description, :name, :time_frequency, :v_type
has_many :report_bodies
has_many :report_heads, :through => :report_bodies
end
class ReportHead < ActiveRecord::Base
attr_accessible :email, :name , :report_bodies_attributes, :report_bodies, :variables_attributes
has_many :report_bodies
has_many :variables, :through => :report_bodies
accepts_nested_attributes_for :report_bodies
end
class ReportBody < ActiveRecord::Base
attr_accessible :report_head_id, :variable_value, :variable_id, :variables_attributes, :report_heads
belongs_to :report_head
belongs_to :variable
end
Update
I updated the model as suggested, and modified the way to call the variables. However im still confused about how to use it in the view, if i do something like:
<%= f.fields_for :variables do |variable| %>
<%= variable.text_field :name, :value => :name, :class => 'text_field' %>
<% end %>
it prints a string instead of the actual name.
You have define wrong name association, your association of ReportBody should be:
belongs_to :report_head
belongs_to :variable
This is not correct:
#report_head.report_bodies.build(:variable_id => a.id,:report_head_id =>#report_head.id)
chang it to:
#report_head.variables.build(:variable_id => a.id)
it's better, you don't have to set report_head_id. And this is wrong:
#report_head.report_bodies.variables
If you want to get all variables belong to #report_head, you just need using:
#report_head.variables