Rails: Association between Category, Subcategory, and Lawyer - ruby-on-rails

I have a vast list of Lawyers, Categories, and Subcategories.
Hint (so you could have a clue if my associations are okay)
On Categories Table, I do not want to see a column on Categories Table referencing Subcategories.
On Subcategories Table, I do not want to see a column on Subcategories Table referencing Categories.
Not all Categories has Subcategories. i.e. some don't have subcategories as seen in the picture.
I have 2 separate forms creating category and subcategory.
I added category_id and subcategory_id as foreign keys to my lawyers table. Such that I can choose from lawyers form upon create, the category or subcategory a lawyer will belong to as soon in the image.
Also note: A Subcategory could be created at any time, any day, for Categories not having Subcategory, as well as new Subcategories under Categories already having some Subcategories, and lawyers will be placed under them.
The image is a replica of my index/homepage I am having at the moment, at least before number 6 above takes effect any time any day, and I hope to use loop to make this view happen.
Pictorial understanding of what I am trying to do:
Here are my relationships between 3 models
class Lawyer < ActiveRecord::Base
belongs_to :category
belongs_to :subcategory
end
class Category < ActiveRecord::Base
has_many :lawyers
end
class Subcategory < ActiveRecord::Base
#belongs_to :category #Do I want "category_id" in Subcategories Table?
has_many :lawyers
end
Question
Is my association on those 3 models okay for the Hint I gave? This is
pretty confusing.

You don't need a Subcategory model/table, specially if they have the same columns. Your categories table should have a parent_id column. A category is a subcategory when it has a parent_id value pointing to another category record. Categories with a NULL parent_id are the top level categories.
Example
class Lawyer < ActiveRecord::Base
belongs_to :category
end
class Category < ActiveRecord::Base
has_many :lawyers
# This is called a self referential relation. This is where records in a
# table may point to other records in the same table.
has_many :sub_categories, class_name: "Category", foreign_key: :parent_id
# This is a scope to load the top level categories and eager-load their
# lawyers, subcategories, and the subcategories' lawyers too.
scope :top_level, -> { where(parent_id: nil).include :lawyers, sub_categories: :lawyers }
end
Note: you should create a migration to add the parent_id column to the categories table. And you can drop the subcategories table.
Now create some of your categories (I'm assuming there's a name column):
cat = Category.create name: "Corporate and Commercial Law"
subcat = Category.new name: "Corporate Tax", parent_id: cat.id
subcat.lawyers << Lawyer.find_by_name("Sabina Mexis")
subcat.save
Example table of contents:
<% Category.top_level.each do |cat| %>
<%= cat.name %>
<% cat.sub_categories.each do |subcat| %>
<%= subcat.name %>
<%= subcat.lawyers.each do |laywer| %>
<%= lawyer.name %>
<% end %>
<% end %>
<% end %>
The above is a simplified example. Hope that helps.
Update
To enhance your form to allow you to create a subcategory and assign its parent category, use a select menu filled with top_level category IDs:
<%= form_for Category.new do |f| %>
<%= f.text_field :name %>
<%= f.select :parent_id, options_from_collection_for_select(Category.top_level, :id, :name) %>
<%= f.submit %>
<% end %>
Check out the docs for options_from_collection_for_select if it's unfamiliar. What it does is build a select menu with the category:id as values and their :name as the text in the menu. Make sure you add :parent_id to your strong parameters to allow mass assignment via params[:category].
The laywer error was just a typo in my example code, it's fixed now.

Related

Rails table with a where clause

I have an employee NonAvailability model and instead of displaying all the non availabilities in the table with
<% #non_availabilities = NonAvailability.all %>
<% #non_availabilities.each do |non_availability| %>
<%= non_availability.employee.full_name %>
<%= non_availability.date %>
<%= non_availability.time %>
<%= non_availability.reason %>
I want to only display the nonavailabilities that correlate to a certain employees id.
How can I do this?
There are multiple ways to retrieve records in rails. For example you can filter NonAvailability with employee_ids using where method
ids = [1,2,3,4] # ids of employee
NonAvailabilty.where(employee_id: ids)
If you want to utilize method chaining, define a has_many and belongs_to association in your Employee and NonAvailability model. Assuming that your design have this specifications.
# employee.rb
class Employee
has_many :non_availabilities
end
# non_availability.rb
class NonAvailability
belongs_to :employee
end
Then you can retrieve all non_availabilites using employee object.
employee = Employee.find_by(id: 1)
employee.non_availabilities
For more info visit this Active Record Association Guide

rails activerecord custom column as foreign/primary key

I have two tables:
manufacturers and products
Both tables have a column "signature" which is unique.
manufacturer model:
class Manufacturer < ApplicationRecord
has_many :products, foreign_key: 'signature', primary_key: 'signature'
end
product model:
class Product < ApplicationRecord
belongs_to :manufacturer, foreign_key: 'signature', primary_key: 'signature'
end
In my products index view I'd like to display the value of column 'active' from table manufacturer.
# products/index.html.erb
<% #products.each do |product| %>
<%= product.manufacturer.active %>
<% end %>
I'm getting the error
undefined method `active' for nil:NilClass
How can I access the active attribute of manufacturer model from products index view? I suppose
product.manufacturer.active
isn't the right way.
In your code example you have to make sure that every product has an manufacturer. Else .active would fail on a manufacturer = nil.
As a fail save if there are products without manufacturer you can use the Safe Navigation Operator &. as mentioned here Available from ruby2.3
product.manufacturer&.active
As an alternative you could make the .active call conditionally like
product.manufacturer.active unless manufactuer.nil?
or
product.manufacturer.active if manufactuer

ruby on rails save group of checkboxes collection select check box

Good Day
i have model
Food
Dayoffer
Food which is records with all foods in our canteen
class Food < ApplicationRecord
belongs_to :supplier
has_many :dayoffer
end
Dailyoffer is restricted set of foods which are offered on some day.
class Dayoffer < ApplicationRecord
belongs_to :food
end
i dont know how to effectively save choices for day
i have idea to use in form collection_check_boxes but dont know how to process it effectively.
schema of db on
https://gist.github.com/netmoleCBA/089950c54a4b8e066da8afc54fa5a62e
Add a WeekDay model that has many offers and seed seven week days in your database :
in your food form:
<%= f.collection_check_boxes(:week_day_ids, WeekDay.all, :id, :name) do |week_day| %>
<%= week_day.label { week_day.check_box } %>
<% end %>
D'ont forget to add week_day_ids in the controller's strong params
params.require(:food).permit(:name, week_day_ids:[])

Selection of elements based on other elements

class Teacher < ActiveRecord::Base
has_many :students
end
class Class <ActiveRecord::Base
has_many :students
end
class Student <ActiveRecord::Base
belongs_to :teacher
belongs_to :class
end
I want to create a list of teachers, and below their names: table with classes from which this teacher has students and number of this students. More or less something like this:
Teacher XYZ:
Class 1A | 3 students
Class 3D | 2 students
How can I check if teacher has students from each class and later count only the students that belongs to both this particular teacher and class?
You can do a query to eager load the classes and students:
#teachers = Teacher.includes(students: :class)
Then I would use group_by in the view to group the students by the class.
<% #teachers.each do |teacher| %>
<%= teacher.name %>
<% teacher.students.group_by(&:class).each do |class, students| %>
<%= class.name %> | <%= students.size %>
<% end %>
<% end %>
I've assumed that a teacher and a class both have a name. There may well be a better way using something like has_many through but I can't see it at the moment.
On another note you shouldn't name your object Class it's going to cause you a lot of problems I'd have thought because it's defined in ruby already http://ruby-doc.org//core-2.2.0/Class.html. I'd call it something like SchoolClass to avoid conflicts.

Ruby on Rails collection_select complexity

i have the following Problem, i Have the following in my customer bill view
<%= f.collection_select :product_id,Product.all,:id,:name %>
This is getting list of all the products from "Product" model and giving option to select from it. But i want to select the list of products from the "StoreOpeningStock" model.
I have these in my model
class Product< ActiveRecord::Base
has_many :store_opening_stocks
has_many :customer_bills
attr_accessible :name
end
class StoreOpeningStock < ActiveRecord::Base
attr_accessible :product_id
belongs_to :product
end
class CustomerBill < ActiveRecord::Base
attr_accessible :product_id
belongs_to :product
accepts_nested_attributes_for :store_opening_stock
end
Can anyone guide me how i can get product name and id from store_opening_stock??? Should i use Helpers??? or is there any other way?? Thanks in advance
I tried using helpers
def getting_prod_names
#sto = StoreOpeningStock.all
for x in #sto
[
['{x.product.title}', '{x.product_id}']
]
end
end
getting following output
<%= f.select :product_id, options_for_select(getting_prod_names) %>
ANy Help?? :)
When you create a form the data used to ccreate a collection_select isnt limited to the Class your going to create an object for. You could simply do the following:
<%= f.collection_select :product_id,StoreOpeningStock.all,:product_id ,:name %>
This should to it for you,...
add this to your StoreOpeningStock class:
def name
return self.product.name unless self.product.nil?
""
end
You need to clarify the relationship between your models...
But just to give you an idea. You can define the collection of products you want to display in your controller, inside the action related to the view (where you are displaying the collection).
Controller:
#products= #here you should call all products you want
Then, your collection of products can be displayed like:
<%= f.collection_select :product_id, #products,:id,:name %>
EDIT
You need to revise the relationship between your models. A product has many customer_bills, but are you sure that each customer_bill belongs to a single product?
I think you have a many-to-many relationship, as a customer_bill can also have many products.
If I understand it right, the solution is to create a ProductLine model between this many-to-many relationship.
Also, what is the difference between Product and StoreOpeningStock? What attributes have you included in the StoreOpeningStock?
If you have created this model only to show the availability of products, why don't you add an attribute in the Product model, for example a boolean column called availability.
So you want to find all products that have a StoreOpeningStock.
This is solely a model concern and have nothing to do with helpers.
class Product
# Find all products that have a StoreOpeningStock
def self.in_stock
find(StoreOpeningStock.product_ids)
end
end
class StoreOpeningStock
# Collect all product ids from stocks
def self.product_ids
uniq.pluck(:product_id)
end
end
Now you can use Product.in_stock instead of Product.all to have the only ones in stock.
I'd add a scope to your products model:
class Product< ActiveRecord::Base
has_many :store_opening_stocks
has_many :customer_bills
attr_accessible :name
scope :having_store_opening_stocks, :joins => : store_opening_stocks, :select => 'distinct product.*', :conditions => 'store_opening_stocks.product > 0'
end
Then you can use Product.all.having_store_opening_stocks to select only products with such stocks, for example:
<%= f.select :product_id, Product.having_store_opening_stocks.map { |product| [product.name, product.id] } %>

Resources