Nested `accepts_nested_attributes_for` hitting `undefined method 'with_indifferent_access'` - ruby-on-rails-5

I'm writing specs for creating a new account. Here's the situation:
Ruby 2.5.0, Rails 5.2.0.rc1
class Account
has_many :accounts_users, inverse_of: :account
has_many :users, through: :accounts_users
has_one :owner, -> { AccountsUser.admins.order(:id) }, class_name: 'AccountsUser'
accepts_nested_attributes_for :owner
end
class AccountsUser
belongs_to :account, inverse_of: :accounts_user
belongs_to :user, autosave: true, inverse_of: :accounts_user
accepts_nested_attributes_for :user
end
class User
has_many :accounts, through: :accounts_users
has_many :accounts_users, autosave: true, dependent: :destroy, inverse_of: :user
accepts_nested_attributes_for :accounts_users, reject_if: :all_blank
end
# AccountsController#account_create_params
params.require(:account).permit(
:plan_id,
:name,
:subdomain,
{
owner_attributes: {
user_attributes: [
:email,
:first_name,
:last_name
]
}
}
)
# rspec account_create_params
let(:valid_account_params) do
{
plan_id: plan.id,
name: 'Name',
subdomain: 'subdomain',
owner_attributes: {
user_attributes: [
email: 'jane#doe.com',
first_name: 'Jane',
last_name: 'Doe'
]
}
}
end
#account = Account.new(account_create_params)
#> NoMethodError: undefined method `with_indifferent_access' for #<Array:0x000056472e0799c0>
from /usr/local/bundle/gems/activerecord-5.2.0.rc1/lib/active_record/nested_attributes.rb:412:in `assign_nested_attributes_for_one_to_one_association'
It has to be complaining about the user_attributes array, and seeing as it's coming from a method called assign_nested_attributes_for_one_to_one_association, Rails seems to be erroneously thinking that the relationship between AccountsUsers and Users is one to one and not one to many.
I've triple checked the associations. What do you guys think? Rails 5.2 bug perhaps?

There were several issues here. I found that permitting parameters and providing them needed different syntax:
def account_create_params
params.require(:account).permit(
:plan_id,
:name,
:subdomain,
{
owner_attributes: {
user_attributes: [
:email,
:first_name,
:last_name,
:password
]
}
}
)
end
vs
let(:valid_account_params) do
{
plan_id: plan.id,
name: 'Name',
subdomain: 'subdomain',
owner_attributes: {
user_attributes: {
email: email_valid,
first_name: 'Jane',
last_name: 'Doe',
password: 'password'
}
}
}
end
A bit confusing there but it works. The inverse_of on AccountsUser was wrong. I needed plural:
belongs_to :account, inverse_of: :accounts_users, optional: true
belongs_to :user, autosave: true, inverse_of: :accounts_users
And I also needed optional: true on the account belongs to, despite accepts_nested_attributes_for setting up the relationship properly. There was a chicken vs egg situation where the AccountsUser was invalid because the Account didn't exist, and the Account couldn't be saved because the AccountsUser was invalid. This may be a Rails 5 'feature'.

Related

Rails simplify a query to get user profile's first_name

I want to retrieve application.applicant.profile.first_name for the applicant and I'm not able to retrieve the profile attribute:first_name using applicant above.
Profile, application are connected by foreign key: user_id to user.Can someone suggest a way?
Here are my associations:
user.rb
class User < ApplicationRecord
has_many :applications
has_one :profile, -> { where role: 'user' }, dependent: :destroy
profile.rb
class Profile < ApplicationRecord
belongs_to :user, :class_name => 'User', :foreign_key => 'user_id'
job.rb
class Job < ApplicationRecord
has_many :applications, :dependent => :destroy
has_many :applicants, :through => :applications, :class_name => 'User'
application.rb
class Application < ApplicationRecord
belongs_to :job
belongs_to :applicant, :class_name => 'User', :foreign_key => 'user_id'
This line isn't correct...
has_one :profile, -> { where role: 'user' }, class_name: 'User', dependent: :destroy
It should be...
has_one :profile, -> { where role: 'user' }, dependent: :destroy
The class_name for :profile is Profile but you don't need to specify it as it can be derived from the symbol by rails.
After numerous permutations and combinations such as polymorphic, select & join statement or even by providing a SQL query, finally realised that it was as simple as a single statement as I knew the user_id of current user:
<% post.applications.each do |papplication| %>
<%= Profile.find_by_user_id(papplication.user_id).first_name %> <% end %>

DB with multiple foreign keys linked to same Model on differents attributes

I am having difficulties building my DB relation, if anyone could give me a little help i would greatly appreciate!
I have one table named Person and another one called Company and Company has many Persons and Person belongs_to Company
Here the trick Company has_many Person threw an attribute called person and has_many Person threw another attribute called administrator
Could be see like
Coca-cola = Company.new
jonathan = Person.new / nicolas = Person.new
Coca-cola : {
person: jonathan,nicolas
administrator: nicolas
}
I did that first migration :
def change
add_reference :persons, :person, index: true
add_reference :persons, :administrator, index: true
add_foreign_key :persons, :companys, column: :person_id
add_foreign_key :persons, :companys, column: :administrator_id
end
then I added this relation to my model
class Company < ApplicationRecord
has_many :persons,
:class_name => "Person",
:foreign_key => "person_id"
has_many :administrators,
:class_name => "Person",
:foreign_key => "administrator_id"
end
and
class Person < ApplicationRecord
belongs_to :person,
:class_name => "Company",
optional: true
belongs_to :administrator,
:class_name => "Company",
optional: true
end
And unfortunately that doesnt working, any lead on what could cause the problem ?
Thanks a lots.
Jonathan.
Let me know if I understood your problem. Requirements are:
Person belongs_to Company
Company has_many Persons
Company has_many Administrators
I guess you could solve with the following code:
class ChangePersons < ActiveRecord::Migration
def change
add_column :persons, :administrator, :boolean, default: false
end
end
class Company < ApplicationRecord
has_many :persons, -> { where(administrator: false) }
has_many :administrators,
class_name: "Person",
foreign_key: "person_id",
-> { where(administrator: true) }
end
class Person < ApplicationRecord
belongs_to :company
end

Rails 4 creating relational record

I am having some issues creating a record from a relational record. This code creates a new user perfectly however it seems that it skips over creating the user's profile all together. It also throws no errors.
any help would be great.
Model
class User < ActiveRecord::Base
has_one :profile
def self.find_for_facebook_oauth(auth)
if user = User.find_by_email(auth.info.email)
user
else
user = User.create( provider: auth.provider,
uid: auth.uid,
email: auth.info.email,
password: Devise.friendly_token[0,20] )
user.build_profile( username: auth.extra.raw_info.username,
first_name: auth.info.first_name,
last_name: auth.info.last_name,
gender: auth.extra.raw_info.gender,
country: auth.extra.raw_info.locale,
image: auth.info.image )
user
end
end
end
Try user.create_profile instead.http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
I forgot that in my Profile class I had a validation for username
model
class Profile < ActiveRecord::Base
# Use friendly_id
extend FriendlyId
friendly_id :username, use: :slugged
belongs_to :users
mount_uploader :image, ProfileImageUploader
validates :username, presence: true, length: {maximum: 16} # <~~
validates :first_name, presence: true, length: {maximum: 255}
validates :last_name, presence: true, length: {maximum: 255}
validates :gender, presence: true, inclusion: %w(male female)
end
My OmniAuth was not giving the username therefore it was rolling back the commit.

Rails belongs_to association is not working

Here is my Course model
class Course < ActiveRecord::Base
attr_accessible :longdescription, :shortdescription, :title, :published_at
has_many :lessons, :foreign_key => 'course_id'
end
And Here is my Lesson model
class Lesson < ActiveRecord::Base
belongs_to :course, :class_name => 'Course'
attr_accessor :course_id
attr_accessible :description, :title, :course_id
end
I creates a lesson that belongs to a course. lesson created successfully
Lesson.create(:title => "testing", :description => "causing problems", :course_id => 1)
But when i fetch a record of lesson I got course_id=nil. Any Help???
<Lesson id: 8, title: "testing", description: "causing problems", course_id: nil, created_at: "2013-03-15 12:56:36", updated_at: "2013-03-15 12:56:36">
you need to remove the attr_accessor :course_id line in your model. If you have this line, it creates the following methods in your model which conflicts with what is defined by default
def course_id
#course_id
end
def course_id=(cid)
#course_id = cid
end
Remove attr_accessor :course_id in your Lesson model. This will override the default behavior of the activerecord.

Rails 3 - trying to create polymorphic has_one association in console

Here's my code:
Models:
class Article < ActiveRecord::Base
attr_accessible :title, :author, :content, :imageable_attributes
has_one :image, as: :imageable, dependent: :destroy
accepts_nested_attributes_for :image, allow_destroy: true
validates_presence_of :title, :content, :author
end
class Image < ActiveRecord::Base
mount_uploader :image, ImageUploader
attr_accessible :image, :caption, :imageable_id, :imageable_type, :article_ref
validates_presence_of :image
belongs_to :imageable, :polymorphic => true
end
Here's what I've tried in console:
article = Article.create!(title: "test", content: "test", author: "test", image_attributes: {image: "test.jpg", caption: "test caption"})
This creates an Article without errors, but if I call:
article.image
I get:
=> nil
If I type in console:
article = Article.new(title: "test", content: "test", author: "test")
article.build_image(image: "test.jpg")
I get:
=> Validation failed: Image image can't be blank
Any help greatly appreciated, I'm very confused!
I believe it's necessary to supply the attachment itself, rather than just the path. As an example,
i = Image.new(
:image => File.join(Rails.root, "test.jpg")
)
i.image
# =>
but
i = Image.new(
:image => File.open(File.join(Rails.root, "test.jpg"))
)
i.image
# => /uploads/tmp/20120427-2155-1316-5181/test.jpg
It's not necessary to use File.open when saving using Multipart POST, though.