Rails nested where clause on join table - ruby-on-rails

I have two models with associations through a join table. Here is the schema...
create_table "group_shots", :force => true do |t|
t.integer "shot_id"
t.integer "group_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "groups", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "shots", :force => true do |t|
t.string "name"
t.integer "comedian_id"
t.string "pic_file_name"
t.string "pic_content_type"
In my groups controller I'm trying to do something like...
def show
#group = Group.find(params[:id])
#shots = Shot.where(GroupShot.where(:group_id => #group.id))
I am getting the error "Cannot visit ActiveRecord::Relation". What is the right way to do this? I'm using Rails 3.2
EDIT
...my models are...
#app/models/group_shot.rb
class GroupShot < ActiveRecord::Base
belongs_to :shots
belongs_to :groups
attr_accessible :group_id, :shot_id
#app/models/group.rb
class Group < ActiveRecord::Base
has_many :shots, through: :group_shot
attr_accessible :name
end
#app/models/shot.rb
class Shot < ActiveRecord::Base
has_many :groups, :through => :group_shot

Assuming you have your group model set up like:
class Group < ActiveRecord::Base
has_many :group_shots
has_many :shots, through: :group_shots
end
class Shot < ActiveRecord::Base
has_many :group_shots
has_many :groups, :through => :group_shots
end
class GroupShot < ActiveRecord::Base
belongs_to :shot
belongs_to :group
end
Then you can do something like
#shots = #group.shots

If the "associations through" is configured right:
#group = Group.find(params[:id])
#shots = #group.shots

Related

Creating record that belongs to 2 seperate tables

So I am trying to create a record that is associated with 2 tables but I cannot seem to get it to work.
Parameters: {"name"=>"asdfasd", "upc"=>"243252353", "availableOn"=>"07/12/2020", "properties"=>[{"name"=>"material", "value"=>"jean"}], "send_datum"=>{"name"=>"asdfasd", "upc"=>"243252353", "availableOn"=>"07/12/2020", "properties"=>[{"name"=>"material", "value"=>"jean"}]}}
class SendDataController < ApplicationController
protect_from_forgery with: :null_session
def save
product = Product.create(name:params[:name], upc:params[:upc].to_i, available_on:params[:availableon])
x=0
while x < params[:properties].length
property = product.properties.create(name:params[:properties][x][:name])
property.product_properties.create(value:params[:properties][x][:value])
x += 1;
end
end
end
This line is the one I cannot seam to get to work:
property.product_properties.create(value:params[:properties][x][:value])
This is my first react on rails project and understanding table assoc. has been a real challenge but I am getting there.
Models:
class Property < ApplicationRecord
belongs_to :product
has_many :product_properties
end
class Product < ApplicationRecord
has_many :properties
has_many :product_properties
end
class ProductProperty < ApplicationRecord
belongs_to :property
belongs_to :product
end
Migration:
class CreateProducts < ActiveRecord::Migration[5.2]
def change
create_table :products do |t|
t.string :name
t.string :upc
t.datetime :available_on
t.timestamps
end
end
end
class CreateProperties < ActiveRecord::Migration[5.2]
def change
create_table :properties do |t|
t.string :name
t.timestamps
end
end
end
class CreateProductProperties < ActiveRecord::Migration[5.2]
def change
create_table :product_properties do |t|
t.string :value
t.timestamps
end
end
end
class AddProductRefToProperties < ActiveRecord::Migration[5.2]
def change
add_reference :properties, :product, foreign_key: true
end
end
class AddProductRefToProductProperties < ActiveRecord::Migration[5.2]
def change
add_reference :product_properties, :product, foreign_key: true
end
end
class AddPropertiesRefToProductProperties < ActiveRecord::Migration[5.2]
def change
add_reference :product_properties, :property, foreign_key: true
end
end
Schema:
ActiveRecord::Schema.define(version: 2018_09_24_163027) do
create_table "product_properties", force: :cascade do |t|
t.string "value"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "product_id"
t.integer "property_id"
t.index ["product_id"], name: "index_product_properties_on_product_id"
t.index ["property_id"], name: "index_product_properties_on_property_id"
end
create_table "products", force: :cascade do |t|
t.string "name"
t.string "upc"
t.datetime "available_on"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "properties", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "product_id"
t.index ["product_id"], name: "index_properties_on_product_id"
end
end
UPDATE::
It is related to the fact that the product_property is getting the property_id from property but is not getting the product_id from the product. How do I fix that?
Any help is greatly appreciated. Thanks!!
The issue was I had my associations set up incorrectly. As #DavidAldridge pointed out I needed to link Property to Product through product property.
class Product < ApplicationRecord
has_many :product_properties
has_many :properties, through: :product_properties
end
class ProductProperty < ApplicationRecord
belongs_to :property, required: false
belongs_to :product, required: false
end
class Property < ApplicationRecord
has_many :product_properties
has_many :products, through: :product_properties
accepts_nested_attributes_for :product_properties
end

ActiveRecord -- user has_many events and belongs to those events as member

I want to set up a relationship where users can start events and then also join them as members. I figured this uses a many to many relationship, but it also has a simple belongs_to relationship from Event to User.
class User < ActiveRecord::Base
has_secure_password
has_many :events # => Owning
has_many :events, through: :members # => Joining
end
class Event < ActiveRecord::Base
belongs_to :user # => event owner
has_many :users, through: :members # => joining users
end
class Member < ActiveRecord::Base
belongs_to :user
belongs_to :event
end
But I'm having trouble getting queries like Event.first.members to work... I can't figure out what's preventing me from using these methods. Am I thinking of these relationships the wrong way? My Schema.rb:
ActiveRecord::Schema.define(version: 20161205220807) do
create_table "events", force: :cascade do |t|
t.string "title"
t.string "location"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "events", ["user_id"], name: "index_events_on_user_id"
create_table "members", force: :cascade do |t|
t.integer "user_id"
t.integer "event_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "members", ["event_id"], name: "index_members_on_event_id"
add_index "members", ["user_id"], name: "index_members_on_user_id"
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.integer "age"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
Updated to fix my mistake
class User < ActiveRecord::Base
has_secure_password
has_many :members
has_many :events, through: :members
end
class Event < ActiveRecord::Base
#belongs_to :user # => event owner
has_many :members
has_many :users, through: :members
class Member < ActiveRecord::Base
belongs_to :user
belongs_to :event
end
If this is giving you a stack level too deep error im guessing the issue is elsewhere. Your logs might have more info.

Associations between three models

I have Article model which should have one gallery, and every gallery should have many pictures. Associations between Article-Gallery, Gallery-Picture models work properly, but I have no idea what I'm doing wrong with Article-Picture association. I've attached my code below.
Article.rb model
class Article < ActiveRecord::Base
belongs_to :gallery
has_many :pictures, through: :galleries
end
Gallery.rb model
class Gallery < ActiveRecord::Base
has_many :pictures, dependent: :destroy
has_many :articles
end
Picture.rb model
class Picture < ActiveRecord::Base
belongs_to :gallery
has_many :articles, through: :galleries
end
Schema.rb
ActiveRecord::Schema.define(version: 20150829181617) do
create_table "articles", force: :cascade do |t|
t.string "title"
t.text "content"
t.integer "author_id"
t.integer "language_id"
t.integer "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "gallery_id"
end
add_index "articles", ["gallery_id"], name: "index_articles_on_gallery_id"
create_table "galleries", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "pictures", force: :cascade do |t|
t.string "image"
t.integer "gallery_id"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
In Rails 4 you can certainly state that an Article:
belongs_to :gallery
has_many :pictures, :through => :gallery
... and that a picture ...
belongs_to :gallery
has_many :articles, :through => :gallery
... allowing you to do both:
#picture.articles
... and ...
#article.galleries
... with both of those being executed as a single query joining through the galleries table.
David's answer is right, belongs_to does work for through associations in Rails 4.
class Article < ActiveRecord::Base
belongs_to :gallery
has_many :pictures, through: :gallery # not :galleries
end
The thing to remember is that the through part of a has_one or has_many is referring to an association, not another model. This is important when you're doing trickier associations.

Unexpected behaviour in rails when defining class_name in habtm

I have two models (Course and Dancer). A course can have many dancers (students) and teachers (also dancers). Teachers can be students of other courses.
I define the tables as follows:
create_table "course_enrollments", :force => true do |t|
t.integer "dancer_id", :null => false
t.integer "course_id", :null => false
t.datetime "attended_on", :null => false
end
create_table "courses", :force => true do |t|
t.string "name", :null => false
t.string "genre"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "courses_teachers", :id => false, :force => true do |t|
t.integer "course_id", :null => false
t.integer "teacher_id", :null => false
end
create_table "dancers", :force => true do |t|
t.string "first_name", :null => false
t.string "last_name", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
And the classes:
class Dancer < ActiveRecord::Base
has_many :course_enrollments
has_many :courses, :through => :course_enrollments
has_many :teachers, :through => :courses
end
class Course < ActiveRecord::Base
has_many :course_enrollments
has_many :dancers, :through => :course_enrollments
has_and_belongs_to_many :teachers, :class_name => 'Dancer'
end
class CourseEnrollment < ActiveRecord::Base
belongs_to :dancer
belongs_to :course
end
Based on the guide (http://guides.rubyonrails.org/association_basics.html), I would expect the teachers attribute of Course to look for the table courses_teachers and use teacher_id as the foreign key. Instead it's looking for courses_dancers and dancer_id, presumably from setting class_name to 'Dancer'. Is this by design or is it a bug? I can get it to work if I instead do:
has_and_belongs_to_many :teachers, :class_name => 'Dancer', :join_table => :courses_teachers
And rename teacher_id to dancer_id in the courses_teachers table
Is there a better approach?
If you look at the api for habtm, there's an option for foreign_key and association_foreign_key. Try the following
has_and_belongs_to_many :teachers, :class_name => 'Dancer', :join_table => :courses_teachers, :foreign_key => :course_id, :association_foreign_key => :teacher_id
I'm not sure if it will work without passing foreign_key option but it probably will so try without it first.

how to search one object and return another related object

I am trying to create search form when user search for a course it returns list of user's names who are taking that course.So i have user table,course table and user-course join table.I want o use metasearch or ransack.But i wonder how i would use these in my case.Thank you in advance.
create_table "users", :force => true do |t|
t.string "firstname"
t.string "email"
t.string "encrypted_password", :limit => 128, :default => "", :null => false
t.string "password_salt", :default => "", :null => false
end
create_table "courses", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "school_id", :null => false
end
create_table "user_courses", :force => true do |t|
t.integer "user_id", :null => false
t.integer "course_id", :null => false
t.boolean "active", :null => false
end
class User < ActiveRecord::Base
has_many :user_courses
has_many :courses, :through => :user_courses
has_many :active_courses, :through => :user_courses, :source => :course, :conditions => {'user_courses.active' => true}
has_many :taken_courses, :through => :user_courses, :source => :course, :conditions => {'user_courses.active' => false}
end
class UserCourse < ActiveRecord::Base
belongs_to :user
belongs_to :course
end
class Course < ActiveRecord::Base
validates_presence_of :name
has_many :user_courses
belongs_to :school
end
You can add this to your Course model:
has_many :users, :through => :user_courses
Then you can get the users from a course like so
Course.find(1).users

Resources