i am stack for days with this, tried everything.
I am trying doing a simple has many associations, but it refuse to work:
what i need is that each orb get an orb_type associated with it.
i generate the scaffolds:
rails generate scaffold orb_type nome
rails generate scaffold orb nome:string descr:text orb_type_id:integer
Make the rake db:migrate,
change the models:
class Orb < ActiveRecord::Base
has_many :orb_types
validates_associated :orb_types
attr_accessible :descr, :nome, :orb_type_id
validates :nome, uniqueness: true, presence: true
end
class OrbType < ActiveRecord::Base
attr_accessible :nome
validates :nome, uniqueness: true, presence: true
belongs_to :orb
end
And then tryed to make it work:
$ rails c
1.9.3-p448 :001 > tipo = OrbType.new nome: "Planeta"
1.9.3-p448 :002 > tipo.save
1.9.3-p448 :003 > tipo = OrbType.find(1)
1.9.3-p448 :004 > planeta = Orb.new nome:"Testname", descr: "TestDescr"
1.9.3-p448 :005 > planeta.orb_type = tipo
and in the last line i get the error:
NoMethodError: undefined method `each' for #<OrbType:0x00000003dc02a0>
Whats the deal? the underscore and rails "conventions" are giving me headaches.
I saw a lot of another similar topics, but none of theirs solutions worked!
Your association is the wrong way round. (Your scaffolds are fine, just need to switch the belongs_to and has_many around.)
Change your models like so:
class Orb < ActiveRecord::Base
belongs_to :orb_type
validates_associated :orb_types
attr_accessible :descr, :nome, :orb_type_id
validates :nome, uniqueness: true, presence: true
end
class OrbType < ActiveRecord::Base
has_many :orbs
attr_accessible :nome
validates :nome, uniqueness: true, presence: true
end
Now an orb can be given a type and a type can be given to many orbs.
Having an orb_type_id in your Orb model is part of the problem. You're saying that Orb has many OrbTypes but the orb_type_id would essentially just allow one and the OrbType belongs to the Orb which means that the OrbType would need the orb_id.
Assuming a many to many relationship is the goal you most likely need an association model:
class Orb < ActiveRecord::Base
has_many :orb_types, :through => :orb_associations
has_many :orb_accociations
validates_associated :orb_types
attr_accessible :descr, :nome, :orb_type_id
validates :nome, uniqueness: true, presence: true
end
class OrbAccociations < ActiveRecord::Base
belongs_to :orb
belongs_to :orb_type
end
class OrbType < ActiveRecord::Base
attr_accessible :nome
validates :nome, uniqueness: true, presence: true
has_many :orb_associations
has_many :orbs, :through => :orb_associations
end
Related
I working on a Rails application, currently we structure the app by modules. Right now we have 2 separate model for users: User and Freight::Customer::User.
I have a new model Freight::Customer::MembershipStatus looks like this:
class Freight::Customer::MembershipStatus < ActiveRecord::Base
belongs_to :customer, class_name: 'Freight::Customer'
belongs_to :created_by, class_name: 'User'
validates :from, presence: true
validates :to, presence: true
validates :customer, presence: true
validates :status, presence: true
end
In this case, the created_by is reference to User. But when the code run membership_status.created_by, rails try to look for the Freight::Customer::User, I think it because Rails try to look for model within the same module first.
Is there a way to config this model to use the outer User model class?
You can get user class using this type, try this.
class Freight::Customer::MembershipStatus < ActiveRecord::Base
belongs_to :customer, class_name: 'Freight::Customer'
belongs_to :created_by, class_name: '::User'
validates :from, presence: true
validates :to, presence: true
validates :customer, presence: true
validates :status, presence: true
end
I'm creating a blog where articles can be responses to other articles. Articles can also be part of groups. However articles do not have to be in a group or be a response to another article.
I'm attempting to follow the Rails docs to create articles as self-joined records.
I created user, group and article scaffolds:
bin/rails g scaffold user username:string email:string birthday:date
bin/rails g scaffold group name:string user:references
bin/rails g scaffold article user:references parent:references title:string subheading:string body:text pub_date:datetime group:references hidden:boolean prompt:boolean
I'm trying to use allow_nil in the model validation.
class Article < ApplicationRecord
belongs_to :user
belongs_to :parent, class_name: "Article"
has_many :replies, class_name: "Article", foreign_key: "parent_id"
belongs_to :group
validates :parent, length: {minimum: 1}, allow_nil: true
validates :group, length: {minimum: 1}, allow_nil: true
end
However when I run the db:seed:
user1 = User.create(username: "pete01",email: "pete01#gmail.com",
birthday:"1980-01-30")
article1 = Article.create!(user:user1, parent:nil, title:"My First Article",
subheading:"This is important", body:"The body of my first article",
pub_date:"2015-12-26", group:nil, hidden:false, prompt:false)
I get this error:
ActiveRecord::RecordInvalid: Validation failed: Parent must exist, Group must exist
Is there somewhere else where I should be telling Rails it does not need to validate Group and Parent?
Solution is to find the file new_framework_defaults.rb, change this to false:
Rails.application.config.active_record.belongs_to_required_by_default = false
#app/models/article.rb
class Article < ActiveRecord::Base
belongs_to :parent, class_name: "Article"
belongs_to :group
validates :parent, presence: true, allow_nil: true
validates :group, presence: true, allow_nil: true
end
Several problems for you:
You're validating parent & group -- these are associative objects.
Your error says "[Object] must exist", which means your validation works -- Rails cannot find a "nil" association (it's expecting objects).
What you should have is either to validate parent_id & group_id, or to validate the presence of the associative object with something like presence.
I've included the following validations I would use:
validates :parent, presence: true, allow_nil: true
validates :group, presence: true, allow_nil: true
You could also try:
validates :parent_id, length: { minimum: 1 }, allow_nil: true
validates :group_id, length: { minimum: 1 }, allow_nil: true
Articles can also be part of groups
You'll probably want to use a has_and_belongs_to_many association for it then:
#app/models/article.rb
class Article < ActiveRecord::Base
has_and_belongs_to_many :groups
end
#app/models/group.rb
class Group < ActiveRecord::Base
has_and_belongs_to_many :articles
end
You'll need a join table called articles_groups with the columns article_id & group_id:
You can create the migration as follows:
$ rails g migration CreateArticlesGroups
# db/migrate/create_articles_groups__________.rb
class CreateArticlesGroups < ActiveRecord::Migration
def change
create_table :articles_groups, id: false do |t|
t.belongs_to :article, index: true
t.belongs_to :group, index: true
end
end
end
$ rake db:migrate
This will allow you to populate the associative objects like this:
#article = Article.find params[:article_id]
#group = Group.find params[:id]
#article.groups << group
This is most likely to be the result of migrating to Rails 5, where the default for belongs_to relations changed. See this answer for details,
allow_nil: true is an option to a validator, not to the validates method. You are using the length: key which will call the LengthValidator with the {minimum: 1} hash as arguments (similar to using validates_length_of).
E.g., use
validates :parent, length: {minimum: 1, allow_nil: true}
instead of
validates :parent, length: {minimum: 1}, allow_nil: true
Note: If using multiple validators, you will need to specify allow_nil for each of them.
Try to remove your validations. Also check your migration for Article. Maybe you have null: false there for group_id and parent_id
class Article < ApplicationRecord
belongs_to :user
belongs_to :parent, class_name: "Article"
has_many :replies, class_name: "Article", foreign_key: "parent_id"
belongs_to :group
end
I'm trying to understand how to implement one-to-many relationship through reference table. I'm looking on this guide I though just write on one model has_many so it will be one-to-many but I'm not completely sure (I wrote something but it's not working). Anyway I'm doing this to save for me a table, and doing it right and not just working.
The model is as following:
Microposts, :id, :content
Tag, :id, :name
Tag_microposts, :tag_id, :micropost_id
Article, :id, :text
Article_microposts, :article_id, :micropost_id
I can do two microposts tables with the id of the tag/article. But I think doing it like this is better and righter.
In the end what's interesting me is to get microposts through tag model. So in the tag_controller be able to do:
def index
#tag = Tag.find(params[:id])
#microposts = #tag.microposts
end
Some code:
class Tag < ActiveRecord::Base
...
has_many :tag_microposts, foreign_key: :tag_id, dependent: :destroy
has_many :microposts, through: :tag_microposts, source: :micropost
...
end
class TagMicropost < ActiveRecord::Base
validates :tag_id, presence: true
validates :micropost_id, presence: true
end
class Micropost < ActiveRecord::Base
belongs_to :user
belongs_to :tag
validates :content, presence: true, length: {minimum: 10, maximum: 250}
validates :user_id, presence: true
end
May I ask why you are using a reference table for this? You can do a one-to-many association with only the two models you are associating. If you want to associate a tag with many posts you can just do this in your models.
class Tag < ActiveRecord::Base
has_many :microposts
end
class Micropost < ActiveRecord::Base
belongs_to :tag
#added in edit
belongs_to :article
validates :content, presence: true, length: {minimum: 10, maximum: 250}
validates :user_id, presence: true
end
This should let you do:
#tag.microposts
Just fine. The forgien key will be stored in your Micro post model so be sure to add the column. You can use an active migration for that. Call the column tag_id, rails should take care of the rest.
Edit*
A added the article association. The problem you raised is only relevant if you need to get the article/tag given the micropost. The code to do that is still pretty simple with this model.
#tag ||= #micropost.tag
Using the conditional assignment operator like this will only assign #tag if the association is there. If you give me more specifics about how these models will be used I can give you a better answer.
I'm having trouble validating a model from a has_many through association. Below are the relevant models:
Broadcast Model
class Broadcast < ActiveRecord::Base
attr_accessible :content,
:expires,
:user_ids,
:user_id
has_many :users, through: :broadcast_receipts
has_many :broadcast_receipts, dependent: :destroy
validates :user_id, presence: true
validates :content, presence: true
end
Broadcast Receipt Model
class BroadcastReceipt < ActiveRecord::Base
belongs_to :broadcast
belongs_to :user
attr_accessible :user_id, :cleared, :broadcast_id
validates :user_id , presence: true
validates :broadcast_id , presence: true
end
There is also an association with Users that have_many broadcasts receipts through broadcast receipts.
The problem appears to be with the following line:
validates :broadcast_id , presence: true
Whenever I try to create a Broadcast, I get a rollback with no error messages given. However, when removing the above line, everything works as expected.
This looks like a problem with the Broadcast not being saved before the Broadcast Receipts are being created.
Is there any way I'd be able to validate the broadcast_id is set on the receipt model?
This appears to be the same issue discussed here: https://github.com/rails/rails/issues/8828, which was solved by adding :inverse of to the has_many associations to the join model.
There might be some problem in your code structuring. You could give this version a try.
class Broadcast < ActiveRecord::Base
# I assume these are the recipients
has_many :broadcast_receipts, dependent: :destroy
has_many :users, through: :broadcast_receipts
# I assume this is the creator
validates :user_id, :content, presence: true
attr_accessible :content, :expires, :user_id, :user_ids
end
class BroadcastReceipt < ActiveRecord::Base
belongs_to :broadcast
belongs_to :user
# You should be able to validate the presence
# of an associated model directly
validates :user, :broadcast, presence: true
attr_accessible :cleared
end
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