Sorting based on column in join model in Rails - ruby-on-rails

I followed this RailsCast to make a sortable list of items, which works great for one model, but I need to sort items that are organized by a join model, and can't figure out how to do it. Here is an example:
I want to organize all the cycles that are in a program by the cycle_order column.
The cycle_order column is in the cycles_programs table
For good measure, see picture of the join table at the bottom.
class Cycle
has_many :cycles_programs
has_many :programs, :through => :cycles_programs
accepts_nested_attributes_for :programs
accepts_nested_attributes_for :cycles_programs, allow_destroy: :true
class CyclesProgram
belongs_to :program
belongs_to :cycle
class Program
has_many :cycles_programs
has_many :cycles, :through => :cycles_programs
accepts_nested_attributes_for :cycles
accepts_nested_attributes_for :cycles_programs, allow_destroy: :true
Here is the Schema:
create_table "programs", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "cycles_programs", :force => true do |t|
t.integer "program_id"
t.integer "cycle_id"
t.integer "cycle_order"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "cycles", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end

Add a default scope to CyclesGroup
default_scope -> { order(:group_order) }

And the answer is so simple. Just add default_scope -> { order(:cycle)order) } to the CyclesProgram model

Related

Looking for a review of my ActiveRecord relations

I recently just started learning RoR and I am creating a hobby project.
So some quick background: Each customer is identified by an account number. Each product sale has an account number attributed with it and the products table contains all the specific product data.
My question is - with the format I have now, is this the proper way I should be linking these tables? One of the issues I am having is filtering a group of sales based on product major. So say I have a customer and I only want to view product sales where the major is "commercial", how do I go about filtering this data? See the scope I created - but I am not sure how to use it.
class Product < ActiveRecord::Base
has_many :product_sales, :primary_key => :prodnum, :foreign_key => :prodnum
has_many :customers, through: :sales
scope :commercial_products, -> { where(major: 'Commercial') }
end
class ProductSale < ActiveRecord::Base
belongs_to :customer, :foreign_key => :account
belongs_to :product, :foreign_key => :prodnum, :primary_key => :prodnum
end
class Customer < ActiveRecord::Base
has_many :product_sales, :primary_key => :account, :foreign_key => :account
has_many :products, through: :product_sales
end
and my schema
create_table "customers", force: :cascade do |t|
t.integer "account"
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "product_sales", force: :cascade do |t|
t.integer "account"
t.string "month"
t.string "prodnum"
t.integer "sales"
t.integer "qtyshipped"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "products", force: :cascade do |t|
t.string "pcatcode"
t.string "pcatname"
t.string "major"
t.string "prodline"
t.string "brand"
t.string "tier"
t.string "prodnum"
t.string "proddesc"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
... I have a customer and I only want to view product sales where the major is "commercial", how do I go about filtering this data?
This should do it:
#customer.product_sales.where(product: {major: 'Commercial'})
PS. Your models look correct, but this bit
has_many :customers, through: :sales
# Probably you meant: through: product_sales

Why wont counter_cache work

class FixedLineItem < AR
belongs_to :fee_table, :class_name => 'FixedFeeTable',
:foreign_key => 'fixed_fee_table_id',
:inverse_of => :line_items,
:counter_cache => :fixed_line_items_count
end
class FixedFeeTable < AR
has_many :line_items, :class_name => 'FixedLineItem',
:inverse_of => :fee_table
end
Given the above, why does #fixed_fee_table.line_items.size still access the db? I can see it performing a COUNT operation in the console.
If i rename the has_many association to has_many :fixed_line_items, it works as expected.
Am i missing an option somewhere? I cant find any mention through googling however.
EDIT
This is on rails 3.2.14
and my schema for the two tables
create_table "fixed_fee_tables", :force => true do |t|
t.string "kind"
t.integer "total_amount_cents"
t.integer "fee_summary_id"
t.string "currency"
t.integer "final_total_amount_cents"
t.integer "fixed_line_items_count", :default => 0, :null => false
end
create_table "fixed_line_items", :force => true do |t|
t.string "description"
t.integer "quantity"
t.integer "price_cents"
t.integer "fixed_fee_table_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "amount_cents"
t.integer "position"
t.integer "total_adjustment_cents"
t.string "currency"
end

Why does only one of my has_many though models work

I followed http://railscasts.com/episodes/17-habtm-checkboxes-revised?view=asciicast tutorial to set up a has_many through relationship and when I try to access information from one model it works but not from the other.
I can access the Category information from the Product model via #product.category_ids and #product.categories, but the reverse isn't true. I can't access the Product information from the Category model. Using #category.product_ids or #category.products gives me the error NoMethodError: undefined method 'product_ids' for #<Category:0x007fa70d430e98>
Product.rb
class Product < ActiveRecord::Base
attr_accessible :category_ids
has_many :categorizations
has_many :categories, through: :categorizations
accepts_nested_attributes_for :categorizations, :allow_destroy => true
end
Category.rb
class Category < ActiveRecord::Base
attr_accessible :product_ids
has_many :categorizations
has_many :products, through: :categorizations
end
-- EDIT --
Schema.rb
ActiveRecord::Schema.define(:version => 20130926192205) do
create_table "categories", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "products", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "categorization", :force => true do |t|
t.integer "product_id"
t.integer "category_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "categorization", ["product_id", "category_id"], :name => "index_categorization_on_product_id_and_category_id", :unique => true
add_index "categorization", ["product_id"], :name => "index_categorization_on_product_id"
add_index "categorization", ["category_id"], :name => "index_categorization_on_category_id"
end
To access the records from each object you should be able to:
#category.products
and
#product.categories
That will give you the associated objects.
product_ids is not a attribute on a category and it does not have accepts_attributes_for :products like your category model so removing attr_accessible :product_ids should fix the error.

Rails ActiveRecord has_many through not working

I have a rails app where users have children. So I had two models: :users and :children.
I used to have a one-to-many relationship (has_many / belongs_to), but I wanted to open it up to a many-to-many relationship where I could store variables about the relationship. So I changed the relationship to a "has_many through" relationship. I created a table called :relationships. A small caveat: I want the foreign_key for user to be :parent_id. Here is how I have them set up:
Schema:
create_table "relationships", :force => true do |t|
t.integer "child_id"
t.integer "parent_id"
t.datetime "created_at"
.
.
.
create_table "users", :force => true do |t|
t.string "email", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "first_name"
t.string "last_name"
.
.
.
create_table "children", :force => true do |t|
t.string "name", :null => false
t.integer "parent_id", :null => false
t.datetime "created_at", :null => false
.
.
.
Class Definitions:
user.rb:
has_many :relationships, foreign_key: "parent_id"
has_many :children, :through => :relationships, foreign_key: "parent_id"
child.rb:
has_many :relationships, foreign_key: "child_id"
has_many :parents, :through => :relationships
relationship.rb:
belongs_to :parent, class_name: "User", :foreign_key => :parent_id
belongs_to :child, class_name: "Child", :foreign_key => :child_id
Now when I choose a specific user and try to get user.children, I get [] in response. If I try to add new children, it doesn't work either. I can define the parent and the child, but when it tries to save, It cannot associate the two. It doesn't see the parent, so I get the error:
*ActiveRecord::StatementInvalid (PG::Error: ERROR: null value in column "parent_id" violates not-null constraint*
If I switch the Class definitions back to a one-to-many setup, it accesses the children just fine. I don't understand what the problem is. Any help would be very appreciated.
Thanks
How are you building the relationship? #user.children works for me with the given example when I create the relationship as follows:
#user.relationships.build(child_id: ...)
in children table parent_id should be allowed to take null if you want create children as nested attributes.
Change
create_table "children", :force => true do |t|
t.string "name", :null => false
t.integer "parent_id", :null => false
t.datetime "created_at", :null => false
end
To
create_table "children", :force => true do |t|
t.string "name", :null => false
t.integer "parent_id"
t.datetime "created_at", :null => false
end

unknown attribute: user_id

I'm getting the error unknown attribute: user_id durring execution of current_user.stories.build
class User < ActiveRecord::Base
has_many :stories, class_name: 'Story', foreign_key: 'user_id', dependent: :destroy
...
class Story < ActiveRecord::Base
belongs_to :user, class_name: 'User', foreign_key: 'user_id'
...
schema.rb
create_table "stories", :force => true do |t|
t.string "responsible"
t.string "descr"
t.string "state"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "users", :force => true do |t|
t.string "email"
t.string "password_digest"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "name"
end
It doesn't contain 'user_id' field. Any ideas?
Kulbir is correct that you need to define a user_id column in your stories table, but doesn't explain the way to do that.
The correct way to make that change is to create a new migration. By convention, it should be called add_user_id_to_stories and would be created as follows (assuming you're using Rails 3+):
rails generate migration add_user_id_to_stories
If you run that, it should actually generate a migration that already contains the change you need to make, which should be something like:
add_column :stories, :user_id, :integer
As an aside when you're following the Rails conventions concerning association naming, which you are, you can actually skip a lot of the extra specification. In the User model, you can specify just has_many :stories and in the Story model specify belongs_to :user. Rails will assume the same class names and foreign keys you've specified.
You should have a user_id field in your stories table like below to define the association in your models.
create_table "stories", :force => true do |t|
t.integer "user_id"
t.string "responsible"
t.string "descr"
t.string "state"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
...
end
Edit
Check Emily's answer for detailed explanation.
you should use the new syntax and pass the fieldtype as symbol
add_column :stories, :user_id, :integer

Resources