Join model not getting created properly using accepts_nested_attributes_for - ruby-on-rails

I have a User model and a Project model joined with the Ownership model using has_many :through. I am trying to set an Ownership attribute's value as I create an association between a User and a Project by using accepts_nested_attributes_for.
Here is my User model:
class User < ActiveRecord::Base
attr_accessible :name, :email, :admin, :projects
has_many :ownerships
has_many :projects, :through => :ownerships
accepts_nested_attributes_for :projects
Here is my ownership model:
class Ownership < ActiveRecord::Base
attr_accessible :owner_type
belongs_to :project
belongs_to :user
validates :user_id, :presence => true
validates :project_id, :presence => true
validates :owner_type, :presence => true
end
and my project model:
class Project < ActiveRecord::Base
attr_accessible :name, :description
has_many :ownerships
has_many :users, :through => :ownerships
and this is how I'm trying to set the owner_type value of the ownership model as its being created:
current_user.ownerships.create(:owner_type => 'designer', :project => #project)
for some reason this isn't creating the ownership join model or (obviously) setting the owner_type value of the ownership model. What can I do to fix this?

Related

Ruby on rails Query related

I have 2 Models
FOLDERS
:name
:parent_id
AUTHFOLDERS
:folder_id
:company_id
:user_id
:role #for sharing
class Folder < ActiveRecord::Base
has_many :authfolders
has_many :companies, :through => :authfolders
accepts_nested_attributes_for :authfolders
validates :name, presence: true
end
class Authfolder < ActiveRecord::Base
belongs_to :company
belongs_to :folder
end
How can select "folders" where Authfolders.company_id = x?
You can join with your related table and then set your condition:
Folder.joins(:authfolders).where('authfolders.company_id = :company_id', company_id: x)

Rails sum Expenses which belongs to Projects and Users

Given is a User Model who has_many Projects.
each Projects belongs_to a User
joined by a Assigned_projects Model
each Project has_many Expenses which belongs to a Project and a User
User Model:
class User < ActiveRecord::Base
has_many :assigned_projects
has_many :projects, :through => :assigned_projects
has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end
Project Model:
class Project < ActiveRecord::Base
belongs_to :user
has_many :assigned_projects
has_many :users, :through => :assigned_projects
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
has_many :expenses
end
join Model:
class AssignedProject < ActiveRecord::Base
attr_accessible :project_id, :user_id, :position, :project
belongs_to :user, class_name: "User"
belongs_to :project, class_name: "Project"
validates :user_id, presence: true
validates :project_id, presence: true
end
Expenses Model:
class Expense < ActiveRecord::Base
belongs_to :project
belongs_to :user
end
Sum all Expenses of a project is easy:
#current_project.expenses.sum(:amount)
I want to list the sum of all Expenses each User added.
The Question is how to sum all Expenses for each user who is assigned to the Project.
I'am looking for something like:
#current_user.#current_project.expenses.sum(:amount)
I assume you are trying to do the following. If not, please explain your question a bit more.
#current_project.expenses.where(user_id: #current_user.id).sum(:amount)

Self referenced has_many and deleting join records when any side of relation is destroyed

I have Board model. Each Board can be Source for other Board. This relationship is saved in Feed table.
class Board < ActiveRecord::Base
belongs_to :user
has_many :links, dependent: :destroy
has_many :feeds, dependent: :destroy
has_many :sources, through: :feeds
attr_accessible :description, :name, :user_id
validates :name, presence: true
end
class Feed < ActiveRecord::Base
belongs_to :board
belongs_to :source, class_name: "Board"
attr_accessible :board_id, :source_id
end
When I destroy Board record, then it destroys corresponding feeds. But how to do this the same but for source ?
Why don't you use :dependent => :destroy too?
Read Deleting from associations: has_many, has_one and belongs_to associations support the :dependent option
If that doesn't work you might also be able to use a ActiveRecord Callbacks:
after_destroy do |record|
other = BoardsSources.find_by_board_id_and_source_id(record.board_id, record.source_id)
other.destroy if other
end

Failing validations in join model when using has_many :through

My full code can be seen at https://github.com/andyw8/simpleform_examples
I have a join model ProductCategory with the following validations:
validates :product, presence: true
validates :category, presence: true
My Product model has the following associations:
has_many :product_categories
has_many :categories, through: :product_categories
When I try to create a new product with a category, the call to #product.save! in the controller fails with:
Validation failed: Product categories is invalid
When I remove the validations, everything works and the join models are saved correctly.
I'm using strong_parameters but I don't think that should be related to this issue.
This is a "racing condition" in the callback chain.
When you create a product it doesn't have any id before it is saved, therefore there is no product in the scope of ProductCategory.
Product.new(name: "modern times", category_ids:[1, 2]) #=> #<Product id: nil >
At that stage of validation (before saving), ProductCatgory cannot assign any id to it's foreign key product_id.
That's the reason you have association validations : so that the validation happens in the scope of the whole transaction
UPDATE: As said in the comment you still can't ensure presence of a product/category. There's many ways around depending on why you want do this (e.g direct access to ProductCategory through some form)
You can create a flag to have validates :product, presence: true, if: :direct_access?
or if you can only update them: validates :product, presence: true, on: "update"
create your product first (in the products_controller) and add the categories after
... But indeed these are all compromises or workarounds from the simple #product.create(params)
Specifying inverse_of on your joining models has been documented to fix this issue:
https://github.com/rails/rails/issues/6161#issuecomment-6330795
https://github.com/rails/rails/pull/7661#issuecomment-8614206
Simplified Example:
class Product < ActiveRecord::Base
has_many :product_categories, :inverse_of => :product
has_many :categories, through: :product_categories
end
class Category < ActiveRecord::Base
has_many :product_categories, inverse_of: :category
has_many :products, through: :product_categories
end
class ProductCategory < ActiveRecord::Base
belongs_to :product
belongs_to :category
validates :product, presence: true
validates :category, presence: true
end
Product.new(:categories => [Category.new]).valid? # complains that the ProductCategory is invalid without inverse_of specified
Adapted from: https://github.com/rails/rails/issues/8269#issuecomment-12032536
Pretty sure you just need to define your relationships better. I still might have missed some, but hopefully you get the idea.
class Product < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
validates :name, presence: true
validates :description, presence: true
validates :color_scheme, presence: true
belongs_to :color_scheme
has_many :product_categories, inverse_of: :product
has_many :categories, through: :product_categories
end
class ProductCategory < ActiveRecord::Base
belongs_to :product
belongs_to :category
validates_associated :product
validates_associated :category
# TODO work out why this causes ProductsController#create to fail
# validates :product, presence: true
# validates :category, presence: true
end
class Category < ActiveRecord::Base
has_many :product_categories, inverse_of: :category
has_many :products, through: :product_categories
end

Rails3 has_many through working on local but fail on heroku

i'm using sqlit3 for local and Postgre for heroku.
Everything works fine until i upload my files to heroku. Here is my model.
class User < ActiveRecord::Base
belongs_to :unit
has_friends
end
class Unit < ActiveRecord::Base
attr_accessible :unit, :floor
has_many :users
belongs_to :block
end
class Block < ActiveRecord::Base
attr_accessible :block, :units_attributes
has_many :units, :dependent => :destroy
accepts_nested_attributes_for :units, allow_destroy: true
belongs_to :postalcode
end
class Postalcode < ActiveRecord::Base
attr_accessible :postalcode, :blocks_attributes
has_many :blocks, :dependent => :destroy
accepts_nested_attributes_for :blocks, allow_destroy: true
belongs_to :neighbourhood
end
class Neighbourhood < ActiveRecord::Base
attr_accessible :name, :streetname, :postalcodes_attributes
has_many :postalcodes, :dependent => :destroy
has_many :blocks, :through => :postalcodes
has_many :units, :through => :blocks
has_many :users, :through => :units
accepts_nested_attributes_for :postalcodes, allow_destroy: true
validates :name, :presence => true
validates :streetname, :presence => true
end
i troubleshooted and found that the problem is with this method in the controller.
#neighbours = current_user.unit.block.postalcode.neighbourhood.users
Although #neighbours = current_user.unit.block.postalcode.neighbourhood works perfectly fine.
Please help, i'm desperate, i have tried googling for it one whole day.
Check out this answer to a similar issue
It is quite likely the error is coming up from WHERE "postalcodes"."neighbourhood_id" = 1 which indicates that neighbourhood_id in postalcodes table is created as a String, instead of an integer.
Follow the steps mentioned in the answer accordingly, and change it to an Integer.

Resources