Ruby on Rails Nested Form - ruby-on-rails

I have three Models: Deal, Zipcode, DealIncludeZipcode.
Now, the association looks like below:-
Deal Model:
class Deal < ActiveRecord::Base
has_many :deal_include_zipcodes, dependent: :destroy
has_and_belongs_to_many :zipcodes, dependent: :destroy
accepts_nested_attributes_for :deal_include_zipcodes,:reject_if => :reject_include_zipcodes, allow_destroy: true
private
def reject_include_zipcodes(attributes)
if attributes[:deal_id].blank? || attributes[:zipcode_id].blank?
if attributes[:id].present?
attributes.merge!({:_destroy => 1}) && false
else
true
end
end
end
end
class Zipcode < ActiveRecord::Base
has_and_belongs_to_many :deals
end
class DealIncludeZipcode < ActiveRecord::Base
belongs_to :deal
belongs_to :zipcode
end
Now in view I have a checkbox,on unchecking it I can select multiple zipcode to select from DealIncludeZipcode.But when I save the data it is not saving.
I have used migration for joining Zipcode and Deal Model in which my exclude zipcode functionality is working correctly.
Please provide a soloution.I have tried various method but didn't got succeed.

The whole point of has_and_belongs_to_many is that you don't have a model which joins the two parts.
class Deal < ActiveRecord::Base
has_and_belongs_to_many :zipcodes
end
class Zipcode < ActiveRecord::Base
has_and_belongs_to_many :deals
end
Would join through a "headless" table called deals_zipcodes. If you want to have a join model you need to use has_many :through instead.
class Deal < ActiveRecord::Base
has_many :deal_zipcodes, dependent: :destroy
has_many :zipcodes, through: :deal_zipcodes
end
class DealZipcode < ActiveRecord::Base
belongs_to :deal
belongs_to :zipcode
end
class Zipcode < ActiveRecord::Base
has_many :deal_zipcodes, dependent: :destroy
has_many :deals, through: :deal_zipcodes
end

I think Max's right. So your migration should be
create_table :deals do |t|
t.string :name
...
end
create_table :zipcodes do |t|
t.string :zipcode
...
end
create_table :deals_zipcodes do |t|
t.belongs_to :deal, index: true
t.belongs_to :zipcode, index: true
end
And your models should be
class Deal < ActiveRecord::Base
has_and_belongs_to_many :zipcodes
end
class Zipcode < ActiveRecord::Base
has_and_belongs_to_many :deals
end
You should probably take a look at the ActiveRecord guide, where you'll find more explanation.

Related

Implement a "Likes system" in rails

I'm trying to figure out how to setup the following. A user can create a review and then like his review or like other reviews if he wants to. I came up with the following setup:
class Like < ApplicationRecord
belongs_to :user
belongs_to :review
end
class User < ApplicationRecord
has_many :reviews
has_many :likes
has_many :liked_reviews, through: :likes, source: :review
end
class Review < ApplicationRecord
belongs_to :user
has_many :likes
has_many :liking_users, :through => :likes, :source => :user
end
class CreateLikes < ActiveRecord::Migration[6.0]
def change
create_table :likes do |t|
t.references :user, index: true
t.references :likes, index: true
t.integer :review_id
t.timestamps
end
end
end
I'm pretty sure that the model associations I came up with are correct, but I'm not so sure about the like table. Can someone please review the above and tell me if the model associations and like table are correct? Thanks in advance!

Trouble with model associations

The goal is for a shop to create rewards and associate each reward to a follower of his choice. This is my setup:
class Shop < ApplicationRecord
has_many :rewards
has_many :follows
has_many :users, through: :follows
end
class Reward < ApplicationRecord
belongs_to :shop
end
class Follow < ApplicationRecord
belongs_to :shop
belongs_to :user
has_many :reward_participant
end
class User < ApplicationRecord
has_many :follows
has_many :shops, through: :follows
end
I created this model in order to capture the reward and follower association.
class RewardParticipant < ApplicationRecord
belongs_to :reward
belongs_to :follow
end
And I have created the following migrations:
class CreateRewards < ActiveRecord::Migration[6.0]
def change
create_table :rewards do |t|
t.string :title
t.text :body
t.date :expires
t.integer :shope_id
t.timestamps
end
end
end
class CreateRewardParticipants < ActiveRecord::Migration[6.0]
def change
create_table :reward_participants do |t|
t.integer :reward_id
t.integer :follow_id
t.timestamps
end
end
end
I'm having trouble figuring out if this is the correct approach to the model associations and migrations. Thanks for the help in advance!
Generally you are right.
We want users to follow a shop, and a shop can create rewards and grant many rewards to many followers.
1. Visual schema:
2. Model associations (complete version)
user.rb
has_many :follows
has_many :reward_follows, through: :follows
has_many :rewards, through: :reward_follows # NOT through shops
has_many :shops, through: :follows
follow.rb
belongs_to :user
belongs_to :shop
has_many :reward_follows
shop.rb
has_many :rewards
has_many :reward_follows, through: :rewards # NOT through follows
has_many :follows
has_many :users, through: :follows
reward.rb
has_many :reward_follows
belongs_to :shop
has_many :follows, through: :reward_follows
has_many :users, through: :follows
3. Do not use date field. Use datetime field.
Justification: https://www.ruby-forum.com/t/time-without-date/194146
This personally saved me hours of work long-term.

RoR Many to many association

I have Category and Specification models and many to many association via CategoriesSpecifications table which looks like this:
create_table :categories_specifications, id: false do |t|
t.belongs_to :specification, null: false
t.belongs_to :category, null: false
t.integer :status, null: false, default: 0
end
What is best practice and shortest way to select all specifications via Category
#category = Category.first
#category.specifications # this is the shortest way to select all specifications via Category
Make sure the associations are declared in your models, of course:
class Category < ActiveRecord::Base
has_many :categories_specifications
has_many :specifications, through: :categories_specifications
end
class Specification < ActiveRecord::Base
has_many :categories_specifications
has_many :categories, through: :categories_specifications
end
class CategoriesSpecification < ActiveRecord::Base
belongs_to :category
belongs_to :specification
end
Recommended reading: http://guides.rubyonrails.org/association_basics.html
Assuming you have something like the below:
class Category < ActiveRecord::Base
has_many :specifications
has_many :categories, :through => :categories_specifications
end
class CategoriesSpecification < ActiveRecord::Base
belongs_to :category
belongs_to :specification
end
class Specification < ActiveRecord::Base
has_many :categories_specifications
has_many :categories, :through => :categories_specifications
end
You can simple find the category and than select all specifications:
Category.find(1).specifications

Rails_admin configuration for polymorphic association

I have Room, Home and Work models as following:
class Home < ActiveRecord::Base
has_many :rooms, as: :available_room
end
class Work < ActiveRecord::Base
has_many :rooms, as: :available_room
end
class Room < ActiveRecord::Base
belongs_to :available_room, polymorphic: true
end
The migration of Room looks as following
class CreateRoom < ActiveRecord::Migration
def change
create_table :rooms do |t|
t.integer :area
t.references :available_room, polymorphic: true
t.timestamps
end
end
end
Now, I want to configure the Home model, using RailsAdmin, and be able to specify a number of available rooms as well as areas.
How can do it via rails_admin in the model Home?
Thanks!
class Room < ActiveRecord::Base
belongs_to :available_room, :polymorphic => true, :inverse_of => :rooms
end
class Home < ActiveRecord::Base
has_many :rooms, :as => :available_room, :inverse_of => :available_room
rails_admin do
field :rooms
end
end
Try something like this. RailsAdmin should render a pretty widget for adding new records.

Rails HABTM middle values

I have to following relationship:
class Course < ActiveRecord::Base
attr_accessible :name
has_and_belongs_to_many :users
end
class User < ActiveRecord::Base
attr_accessible :name
has_and_belongs_to_many :courses
end
Then I have the following table:
create_table :courses_users, :force => true, :id => false do |t|
t.integer :user_id
t.integer :course_id
t.integer :middle_value
end
How can I access (edit/update) the middle value in the many to many record?
HABTM should be used to only store the relation. If you have any fields you want to store in the relation, you should create another model, eg. CourseSignup. You would then use this model to create a has_many :through => :course_signups relation, so your models would look like this:
class Course < ActiveRecord::Base
has_many :course_signups
has_many :users, :through => :course_signups
end
class CourseSingup < ActiveRecord::Base
belongs_to :course
belongs_to :user
end
class User < ActiveRecord::Base
has_many :course_signups
has_many :courses, :through => :course_signups
end
Then you can add your middle_value in the CourseSignup model.
You can find more details in the guide to ActiveRecord associations.
You want a has_many :though, not a HABTM.
A HABTM does not have a join model, but a has_many :through does. Something like:
class Course < ActiveRecord::Base
has_many :enrollments
has_many :users, :through => :enrollments
end
class Enrollment < ActiveRecord::Base
belongs_to :course
belongs_to :user
end
class User < ActiveRecord::Base
has_many :enrollments
has_many :courses, :through => :enrollments
end

Resources