category structure - ruby-on-rails

I am having trouble with some theory.
I have a model called Promos, and I also have a model called Categories.
I want the admin to be able to create set Categories from which the users will select in a dropdown to assign the Promo. So Promos will belong to a Category but the assignment ought to happen in the create.
What is the recommended structure?

To ensure that every Promo has a Category:
class Category < ActiveRecord::Base
has_many :promos
end
class Promo < ActiveRecord::Base
belongs_to :category
validates_association_of :category
end
How to set the Category at Promo creation time
promo = Promo.new(:category => #category)
As far as forms go:
<% form_for :promo do |f| %>
<%= f.collection_select :category_id, Category.all, :id, :name, :prompt => "Choose a category" %>
...
Other promo fields
...
<% end %>
Matching controller code:
class PromosController < ActionController
def create
#promo = Promo.create(params[:promo])
...
redirect or render whether #promo was successfully created
...
end
end

A user has_many a promos, which belongs to a category.
A category has_many promos.
Such as:
class User < Activerecord::Base
has_many :promos
class Promo < Activerecord::Base
belongs_to :user
belongs_to :category
class Category < Activerecord::Base
has_many :promos

Related

Rails: Simple form - multilevel collection grouped_select

I have the following associations setup:
class Category < ApplicationRecord
has_many :child_categories
end
class ChildCategory < ApplicationRecord
belongs_to :category
has_many :subcategories
end
class Subcategory < ApplicationRecord
belongs_to :child_category
has_many :child_subcategories
end
class ChildSubcategory < ApplicationRecord
belongs_to :subcategory
end
An example of the above structure is: Apparel(category) - Clothing(child category) - Men(subcategory) - Tshirts(child subcategory).
I have a simple form where I create a product and I would like to associate that product with a child subcategory from a collection grouped_select input. Basically this input will be multileveled, for example: Clothing(cant select this) under that Men(cant select this) and after that Tshirts(I will be able to select this and associate a product with a child subcategory).
I'm kind of stuck on how to populate the collection grouped_select input, I can only get it to show the child categories and subcategories with the following. Any ideas how I can show the child subcategories as well?
#categories = ChildCategory.where(id: params[:category])
<%= f.input :category_id, collection: #categories.order(:name), as: :grouped_select, group_method: :subcategories, include_blank: false, include_hidden: false %>

Solution for nested form

I have been stuck on this problem for a while.
Need to make a form for competitions category with custom inputs. It should take all values from Information table and build the inputs, but the tricky part is that it should be saved to Category_informations table.
class Competition < ApplicationRecord
has_many :categories
has_many :informations
end
class Category < ApplicationRecord
belongs_to :competetion
has_many :category_informations
has_many :information, through: competition
end
class CategoryInformation
belongs_to :catagory
belongs_to :information
end
class Information < ApplicationRecord
belongs_to :competetion
has_many :category_informations
end
Competition -> name
Category -> name, competition_id
Information -> name, competition_id
Category_informations -> value, category_id, information_id
Take a look at this gem: https://github.com/plataformatec/simple_form
Simple Form aims to be as flexible as possible while helping you with powerful components to create your forms.
Let's take a simple example:
class Machine < ActiveRecord::Base
has_many :parts , inverse_of: :machine
accepts_nested_attributes_for :parts
end
class Part < ActiveRecord::Base
# name:string
belongs_to :machine
end
With these models, we can use simple_form to update the machine and its associated parts in a single form:
<%= simple_form_for #machine do |m| %>
<%= m.simple_fields_for :parts do |p| %>
<%= p.input :name %>
<% end %>
<% end %>
For 'new' action, build the nested model from the controller:
class MachinesController < ApplicationController
def new
#machine = Machine.new
#machine.parts.build
end
end
Source: https://github.com/plataformatec/simple_form/wiki/Nested-Models
Sounds to me like you're looking for accepts_nested_attributes_for
See:
https://apidock.com/rails/v3.2.3/ActiveRecord/NestedAttributes/ClassMethods/accepts_nested_attributes_for
https://rubyplus.com/articles/3681-Complex-Forms-in-Rails-5
Also, check out the cocoon gem.

Setting limitations across has_many through models

Those are my models:
class User < ActiveRecord::Base
has_many :memberships
has_many :groups, through: :memberships
end
class Group < ActiveRecord::Base
has_many : memberships
has_many :users, through: :memberships
belongs_to :group_type
end
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
class GroupType < ActiveRecord::Base
has_many :groups
end
I would like to assign groups to users. there are several types of groups, users can choose only one group from each type. in the view there should a select tag for each group type (a user don't have to be a member of each of the group types).
I can add a type_id column to the membership model and create a instance for each group for each new user, and then update rows, with something like (for type 1):
<%= form_for (#user) do |f|
<% #membership = Membership.where (user_id: :#user.id, group_type: :1) %>
<%= f.collection_select (:membership, :group_id, Group.all.where(type: 1), :id, :name) %>
<% end %>
(not sure that it will work)
anyway I'm sure there is a better way.. how can I connect the models with the one group for each type limitation? (with, ofcourse, a way to edit existing memberships).
I would appriciate any assistance...
Thank you!
Your model structure look good. You could also include the group_type in the membership and than validate against uniqueness.
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
belongs_to :group_type
validates :user_id, uniqueness: { scope: [:group_id, :group_type_id],
message: "can only join one group of this type." }
end
The form should create a membership.
<%= form_for (Membership.new) do |f|
<%= f.hidden_field :user_id, value: #user.id %>
<%# your selection for a group %>
<% end %>
In the controller you have to load the group from the DB, than add the group_type_id to params and .save -> The validation will handle the rest.

Rails - Issue in has_many through with nested attributes

I am having issue with saving a has_many through relation with nested attributes. Due to complexity and requirment in the application the relation is as follows
Table structure,
agreements:
id
agreement_rooms:
id
agreement_id
room_id
details:
id
agreement_rooms_id
For more clarification, agreement_rooms table is related to many other models which will be having agreement_rooms_id in them.
Rails Associations,
class Agreement < ActiveRecord::Base
has_many :details,:through => :agreement_rooms
accepts_nested_attributes_for :details
end
class AgreementRoom < ActiveRecord::Base
has_many :details
end
class Detail < ActiveRecord::Base
belongs_to :agreement_room
accepts_nested_attributes_for :agreement_room
end
When i try to create a agreements record with details hash in it, i get the following error,
Agreement.last.details.create()
ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection: Cannot modify association 'agreement#details' because the source reflection class 'Detail' is associated to 'agreementRoom' via :has_many.
I am not sure how to get this nested attributed working with has_many through relation for the above example. Please help out to figure the issue.
Thanks in advance.
#app/models/aggreement.rb
class Agreement < ActiveRecord::Base
has_many :agreement_rooms
accepts_nested_attributes_for :agreement_rooms
end
#app/models/agreement_room.rb
class AgreementRoom < ActiveRecord::Base
belongs_to :agreement
belongs_to :room
has_many :details
accepts_nested_attributes_for :details
end
#app/models/room.rb
class Room < ActiveRecord::Base
has_many :agreement_rooms
has_many :agreements, through: :agreement_rooms
end
#app/models/detail.rb
class Detail < ActiveRecord::Base
belongs_to :agreement_room
end
--
#app/controllers/agreements_controller.rb
class AgreementsController < ApplicationController
def new
#agreement = Agreement.new
#agreement.agreement_rooms.build.details.build
end
def create
#agreement = Agreement.new agreement_params
#agreement.save
end
private
def agreement_params
params.require(:agreement).permit(:agreement, :param, agreement_rooms_attributes: [ details_attributes: [:x] ])
end
end
#app/views/agreements/new.html.erb
<%= form_for #agreement do |f| %>
<%= f.fields_for :agreement_rooms do |ar| %>
<%= ar.fields_for :details do |d| %>
<%= d.text_field :x %>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
you need to define both associations:
class Agreement < ActiveRecord::Base
has_and_belongs_to_many :agreement_rooms # or has_many if you prefer
has_many :details,:through => :agreement_rooms
accepts_nested_attributes_for :details
end
check the docs
As i said before the model association design we has was not proper and due to poor maintenance it has to be in the same way, atleast for now. So i had to write a dirty patch to fix it.
Its simply skipping nested attributes for this specific model alone, so it can be saved separately by passing the master record id to this record.
As its a dirty solution i'm not marking it as the answer. Just added it hoping someone can have a solution if needed.
Thanks for the help

accepts_nested_attributes_for - belongs_to, has_many, fields_for

Is there any possible way to use nested_attributes_for in the way show below?
Basically I want to create a person, one or more cars and add details to each car. This is just a mock up, not a very realistic example. I get snagged when trying to build the details for the car as it hasn't been created yet.
Models:
class Person < ActiveRecord::Base
has_many :cars
accepts_nested_attributes_for :car
end
class Car < ActiveRecord::Base
belongs_to :person
has_many :details
accepts_nested_attributes_for :details
end
class Detail < ActiveRecord::Base
belongs_to :car
end
Form:
form_for #person do |f|
#fields
f.fields_for :car do |car|
#fields
car.fields_for :details |detail|
=detail.text_field :content
end
end
end
Have a look at that http://railscasts.com/episodes/196-nested-model-form-part-1?view=asciicast

Resources