Gem fabricator does not fabricate one to many relation objects - ruby

I have the following db setup:
class Booking < ApplicationRecord
belongs_to :customer, foreign_key: 'customerId'
end
And the other side of the equation:
class Customer < ApplicationRecord
attr_accessor :age
has_many :bookings, foreign_key: 'customerId'
end
customerId is the field on the bookings table. This is my fabricator for booking:
Fabricator(:booking) do
customer
provided_service_id { "fake_242150" }
end
The customer fabricator works on its own without referencing the booking fabricator. The strange thing that happens is that the booking fabricator actually creates customers but not booking.

Related

Ruby: Associations to enable querying across 4 models

I've been trying all day to figure this out and not getting anywhere. I have these 4 models. Shop Customer Credit and CreditChange
I want to return the CreditChanges for a shop's customers, NOT the customers. Like this:
latest_changes = Shop.last.customers.credit_changes
I'm trying to join like this, but its returning the customers and not the credit_changes
Shop.last.customers.joins(:credit, :credit_change).where.not(credit_changes: {date: nil})
My models look like the following:
class Shop < ActiveRecord::Base
has_many :customers, dependent: :destroy
class Customer < ActiveRecord::Base
has_one :credit, dependent: :destroy
has_many :credit_changes, through: :credit
belongs_to :shop
class Credit < ActiveRecord::Base
belongs_to :customer
has_many :credit_changes, dependent: :destroy
class CreditChange < ActiveRecord::Base
belongs_to :credit
Where did I go wrong?
You want a has-many-through relationship.
A Shop has many CreditChanges through its Customers.
Try:
class Shop
has_many :customers
has_many :credit_changes, through: :customers
end
#shop.credit_changes
You can read more in the Rails documentation
https://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
Try inverting the way you're looking at things:
CreditChange.joins(:credit => :customer).where(customers: {shop: Shop.last}).where.not(credit_changes: {date: nil})

Define a custom has_many relation

Let's say an application has a User who can Like a Post. But also a Post can be owned by a User (on owner_id). So models would look like
class User < ApplicationRecord
has_many :likes
has_many :posts, through: :likes
end
class Like < ApplicationRecord
belongs_to :user
belongs_to :post
end
class Post < ApplicationRecord
has_many :likes
has_many :users, through: :likes
belongs_to :owner, class_name: 'User'
end
How can I define a relation that would return all users with any correlation to a post?
So trying to replace the users association:
class Post < ApplicationRecord
# no owner_id, lambda is called in an User::ActiveRecord_Relation context
has_many :users, -> { where('users.id = ? OR likes.post_id = ?', owner_id, id) }, through: :likes
# doesn't work because "Relation passed to #or must be structurally compatible."
def users
User.where(id: owner_id).or(users)
end
# works but isn't an association.
def users
User.joins(:likes).where('users.id = ? OR likes.post_id = ?', owner_id, id)
end
end
I'd love to be able to define something that would allow me to write
Post.includes(:users)
without
ActiveRecord::AssociationNotFoundError: Association named 'users' was not found on Post; perhaps you misspelled it?

Setting up my models with has_many through

I have become a little unstuck trying to setup my models with the correct associations, I have 3 models as follows
class Image < ActiveRecord::Base
has_many :categories
end
class Category < ActiveRecord::Base
has_many :image_categories
has_many :images, through: :image_categories
end
class ImageCategory < ActiveRecord::Base
# Holds image_id and category_id to allow multiple categories to be saved per image, as opposed to storing an array of objects in one DB column
belongs_to :image
belongs_to :category
end
The ImageCategory table is my join table as I see it which holds all my image_ids with their corresponding category_ids, as a Image can have multiple Categories
Form to create Image
permit_params :id, :title, :description, :photo,
category_ids: []
form html: { multipart: true } do |f|
inputs do
f.semantic_errors
f.input :title
f.input :description, as: :text, input_html: { rows: 10, cols: 10 }
f.input :categories, as: :check_boxes
end
end
When I try and then create an image, I get the following error:
can't write unknown attribute `image_id`
What error(s) have I made here?
I think the way that you have set up your associations is causing you this issue.
class Image < ActiveRecord::Base
has_many :image_categories
has_many :categories, through: :image_categories
end
class Category < ActiveRecord::Base
has_many :image_categories
has_many :images, through: :image_categories
end
class ImageCategory < ActiveRecord::Base
belongs_to :image
belongs_to :category
end
What your current associations describe is that a category can have many images through image_categories but image and image_categories are associated via category in your model which is not what I think you intend.
As I could see, there is a mistake in Image Model
class Image < ActiveRecord::Base
has_many :categories, through: :image_categories
has_many :image_categories
end
Hope this help you !!!
Just to add there was no need for your join model ImageCategory in this case. Check out has_and_belongs_to_many association (HABTM).
has_many:through is useful in scenarios where you would need to add additonal attributes to your ImageCategory model other than ImageId and CategoryId.
In your scenario, however, HABTM will suffice.

has_one :through and has_many :through

rails -v = 4.0
ruby -v = 2.1.1
I am having some serious problem with has_one :through. All of the google 1st 2 pages link are blue in color ( I have gone through all of them).
My problem is when I try to do
post = Post.last
post.build_user
It say undefined method `build_user'. My classes with associations are as follow.
class Post < ActiveRecord::Base
has_one :user_post
has_one :user, class_name: "User", through: :user_post
accepts_nested_attributes_for :user
end
class UserPost < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
class User < ActiveRecord::Base
has_many :user_posts
has_many :posts, through: :user_posts
end
It would be really great if somebody please help to out to resolve this issue.
Much obliged.
You are attempting to setup a Many-to-Many Relationship between Post and User but your current setup is incorrect.
You need to use has_many instead of has_one in Post model.
class Post < ActiveRecord::Base
has_many :user_posts
has_many :users, through: :user_posts
end
After this you can build the users as:
post = Post.last
post.users.build
UPDATE
You are getting error as undefined methodbuild_user'.because you can only usepost.build_userif association betweenPostandUserishas_one` and defined as below:
class Post < ActiveRecord::Base
has_one :user
end
class User < ActiveRecord::Base
belongs_to :post # foreign key - post_id
end
UPDATE 2
Also, logically A user has_many posts AND A post has one User so your setup should ideally be
class Post < ActiveRecord::Base
belongs_to :user # foreign key - user_id
end
class User < ActiveRecord::Base
has_many :posts
end
After this you can build the posts for a user as:
user = User.last
user.posts.build
To build a user for a post:
post = Post.last
post.build_user

Rails 3.1 - Scope for multiple objects through belongs_to association?

class Item < ActiveRecord::Base
belongs_to :account
belongs_to :category
end
class Category < ActiveRecord::Base
belongs_to :account
has_many :items
end
I'd like to do the following:
#items = #account.items.where(...)
#categories = #items.categories.order(...)
#items.categories should get all categories of #items through the belongs_to association. The best I've come up with is:
#categories = #items.map{|item| item.category }
But isn't there a scope for managing this?
Since you want the categories from an account by going through the items, I think you could do something like
has_many :categories, :through => :items
in your Account model, and then just call account.categories
Also, for the record, the map you're doing there does n+1 queries (it should be something like #categories = #items.includes(:category).map{...}

Resources