ActiveRecord query with multiple joins not recognizing the relations - ruby-on-rails

I am trying to write an ActiveRecord Query that returns all students enrolled in a certain course with the following query:
def self.students_enrolled_in(course_id)
Student
.joins(:enrollments)
.joins(:sections)
.joins(:courses)
.where(sections: { course_id: course_id })
end
the result in the rails console is:
ActiveRecord::ConfigurationError: Can't join 'Student' to association named 'sections'; perhaps you misspelled it?
it seems that the association is made. what am I doing wrong? does the query actually mean that all the join() statements have to relate back to Student, or should ac trace out the relational links?
Professor show page:
<div class="col-md-8">
<h2 class="card-title"><%= #professor.name %></h2>
<% #courses_taught.each do |course| %>
<div class="card mb-4 card-header">
<img class="card-img-top" src="http://placehold.it/750x300" alt="Card image cap">
<h3 class="card-text"><%= course.title %></h3>
</div>
<div class="card-body">
<% course.sections.enrollments.students.each do |student| %>
<p><% student.name %></p>
<% end %>
</div>
<% end %>
</div>
models:
enrollment
class Enrollment < ApplicationRecord
belongs_to :section
belongs_to :student
end
Student:
class Student < ApplicationRecord
has_many :enrollments
end
Professor:
class Section < ApplicationRecord
has_many :enrollments
belongs_to :professor
belongs_to :course
validates_uniqueness_of :professor_id, scope: :course_id
scope :by_professor_id, ->(prof_id) { where('professor_id = ?', prof_id) }
end
Course:
class Course < ApplicationRecord
enum status: { planning: 0, offered: 1 }
scope :offered, -> { where(status: 1) }
scope :planning, -> { where(status: 0) }
belongs_to :department
has_many :sections
has_many :professors, through: :sections
validates :title, :number, :status, :description, presence: true
validates :description, length: { in: 10..500 }
validates :title, :number, uniqueness: { case_sensitive: false }
def self.search(term)
if term
where('title LIKE ?', "%#{term}%").order('title DESC')
else
order('title ASC')
end
end
def self.taught_by(professor_id)
Course
.joins(:sections)
.joins(:professors)
.where(sections: { professor_id: professor_id })
.select('distinct courses.*')
end
end
Schema:
ActiveRecord::Schema.define(version: 20171013201907) do
create_table "courses", force: :cascade do |t|
t.string "title"
t.text "description"
t.string "number"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "status", default: 0
t.integer "department_id"
t.index ["department_id"], name: "index_courses_on_department_id"
end
create_table "departments", force: :cascade do |t|
t.string "name"
t.text "description"
t.text "main_image"
t.text "thumb_image"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "enrollments", force: :cascade do |t|
t.integer "section_id"
t.integer "student_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["section_id"], name: "index_enrollments_on_section_id"
t.index ["student_id"], name: "index_enrollments_on_student_id"
end
create_table "professors", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "status", default: 0
t.integer "department_id"
t.text "bio"
t.index ["department_id"], name: "index_professors_on_department_id"
end
create_table "sections", force: :cascade do |t|
t.integer "number"
t.integer "max_enrollment"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "professor_id"
t.integer "course_id"
t.string "room"
t.index ["course_id"], name: "index_sections_on_course_id"
t.index ["professor_id", "course_id"], name: "index_sections_on_professor_id_and_course_id", unique: true
t.index ["professor_id"], name: "index_sections_on_professor_id"
end
create_table "students", force: :cascade do |t|
t.string "name"
t.decimal "gpa"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "name"
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "roles"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end

Another way to do this is to add some more associations to your Student model:
class Student < ApplicationRecord
has_many :enrollments
has_many :sections, through: :enrollments
has_many :courses, through: :sections
scope :enrolled_in_course, -> (course) { joins(:sections).where(course_id: course.id)
end
You can then find all students enrolled in a course with:
Student.enrolled_in_course(course)

You're over-applying .joins. Try starting from the inside out. First, find the course:
Course.find_by(id: course_id)
Then, find all the sections associated with the course. No need to do a joins here:
Section.where(course: Course.find_by(id: course_id))
Now you do your join:
Student.joins(:enrollments).where(enrollments: {section: Section.where(course: Course.find_by(id: course_id))})
I think that ought to do the trick for you. But, untested. So, give it a go and see if it works.
P.S.: Try posting only the most relevant code. It's not so much fun to sort through a bunch of extraneous stuff.

Related

Rails has_many_through query not returning results

I have some models with a has_many_through join. I am trying to get a list of classification_fields and their properties where the classification_id is in the array I am pasing through. This following query doesn't seem to be getting anything. What am I doing wrong?
Get the parent ids and query the classificationfields:
#parentids = #classification.self_and_ancestors_ids.to_a if params[:class_id].present?
#details = ClassificationField.includes(:classifications).where(classification_id: [#parentids] ) if params[:sub].present?
classification model:
belongs_to :parent, class_name: "Classification", optional: true
has_many :children, class_name: "Classification", foreign_key: "parent_id", dependent: :destroy
has_many :class_fields
has_many :fields, through: :class_fields, source: :classification_field
accepts_nested_attributes_for :fields, allow_destroy: true
has_closure_tree
classification_field model:
has_many :class_fields
has_many :classifications, through: :class_fields
class_fields model:
belongs_to :classification
belongs_to :classification_field
Form where I am rendering dynamic form fields based on the classification fields details:
<%= form.fields_for :properties, OpenStruct.new(#sr.properties) do |builder| %>
<% #details.each do |field| %>
<%= render "srs/fields/#{field.field_type}", field: field, form: builder %>
<% end %>
<% end %>
Schema:
enable_extension "plpgsql"
create_table "class_fieldmembers", force: :cascade do |t|
t.integer "classification_id"
t.integer "classification_field_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "class_fields", force: :cascade do |t|
t.bigint "classification_id", null: false
t.bigint "classification_field_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["classification_field_id"], name: "index_class_fields_on_classification_field_id"
t.index ["classification_id"], name: "index_class_fields_on_classification_id"
end
create_table "classification_fields", force: :cascade do |t|
t.string "name"
t.string "field_type"
t.string "required"
t.string "classification_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "displayname"
end
create_table "classification_hierarchies", force: :cascade do |t|
t.integer "ancestor_id", null: false
t.integer "descendant_id", null: false
t.integer "generations", null: false
t.index ["ancestor_id", "descendant_id", "generations"], name: "classification_anc_desc_idx", unique: true
t.index ["descendant_id"], name: "classification_desc_idx"
end
create_table "classifications", force: :cascade do |t|
t.string "name"
t.string "displayname"
t.text "description"
t.boolean "inuse"
t.integer "sort_order"
t.integer "parent_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "srs", force: :cascade do |t|
t.string "summary"
t.text "description"
t.string "status"
t.string "priority"
t.bigint "user_id", null: false
t.bigint "classification_id", null: false
t.text "properties"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["classification_id"], name: "index_srs_on_classification_id"
t.index ["user_id"], name: "index_srs_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.boolean "admin"
t.string "first_name"
t.string "last_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
add_foreign_key "class_fields", "classification_fields"
add_foreign_key "class_fields", "classifications"
add_foreign_key "srs", "classifications"
add_foreign_key "srs", "users"
Query results from console:
[1] pry(main)> ClassificationField.includes(:classifications).where(classification_id: [1, 6] )
ClassificationField Load (0.7ms) SELECT "classification_fields".* FROM "classification_fields" WHERE "classification_fields"."classification_id" IN ($1, $2) [["classification_id", "1"], ["classification_id", "6"]]
ClassificationField Load (0.6ms) SELECT "classification_fields".* FROM "classification_fields" WHERE "classification_fields"."classification_id" IN ($1, $2) /* loading for inspect */ LIMIT $3 [["classification_id", "1"], ["classification_id", "6"], ["LIMIT", 11]]
=> #<ClassificationField::ActiveRecord_Relation:0x4a10>
Any help is appreciated.
Try this. Convert query result to array of objects using .to_a
#details = ClassificationField.includes(:classifications).where(classification_id: [1, 6] ).to_a
I think I have it now.
#details = ClassificationField.joins(:class_fields).where(class_fields: {classification_id: [#parentids]}).to_a if params[:sub].present?

Creating User Groups on Rails

I'm creating a rails application in which a user can create a group, add contacts, add a contact to that group and subsequently broadcast information out to the users to a group they have created.
I'm at the third stage where I'm now trying to allow the logged in user to add a contact to the group.
I have three models for many to many relationships:
class UserGroups < ApplicationRecord
belongs_to :user
belongs_to :group
end
class Group < ApplicationRecord
belongs_to :user
has_many: :user_groups
has_many: :users, through: :user_groups
validates :title, presence: true
end
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_one_attached :avatar
has_many :groups, dependent: :destroy
has_many :posts, dependent: :destroy
has_many :user_groups
has_many :users, through: :user_groups
before_create :set_circleid
has_many :contactships, dependent: :destroy
has_many :contacts, -> { where contactships: { status: :accepted }}, through: :contactships
has_many :requested_contacts, -> { where contactships: { status: :requested }}, through: :contactships, source: :contact
has_many :pending_contacts, -> { where contactships: { status: :pending }}, through: :contactships, source: :contact
has_many :blocked_contacts, -> { where contactships: { status: :blocked }}, through: :contactships, source: :contact
has_many :contactships_inverse, class_name: 'Contactship', foreign_key: :contact_id
has_many :contacts_inverse, through: :contactships_inverse, source: :user
def all_contacts
contacts + contacts_inverse
end
def has_contactship?(contact)
#return true if the user is a contact
return true if self == contact
contactships.map(&:contact_id).include?(contact.id)
end
def requested_contacts_with?(contact)
return false if self == contact
#we are going to map requested contacts with list of users to see if they include contact_id
requested_contacts.map(&:id).include?(contact.id)
end
def pending_contacts_with?(contact)
return false if self == contact
pending_contacts.map(&:id).include?(contact.id)
end
def contacts_with?(contact)
return false if self == contact
contacts.map(&:id).include?(contact.id)
end
def contact_request(contact)
#unless the contact is not equal to self and contactship does not already exist
unless self == contact || Contactship.where(user: self, contact: contact).exists?
#transaction means that if one fails they both are rolled back
transaction do
#for user to another user (sent request)
Contactship.create(user: self, contact: contact, status: :pending)
#from another user to user (recieve request)
Contactship.create(user: contact, contact: self, status: :requested)
end
end
def accept_request(contact)
transaction do
Contactship.find_by(user: self, contact: contact, status: [:requested])&.accepted!
Contactship.find_by(user: contact, contact: self, status: [:pending])&.accepted!
end
end
def reject_request(contact)
transaction do
Contactship.find_by(user: self, contact: contact)&.destroy!
Contactship.find_by(user: contact, contact: self)&.destroy!
end
end
end
And a method within my group controller (not sure what to do here):
#for adding a user to a group?
def add_user
#search for the group?
#group = Group.find(params[:id])
#add a user to that group via user_groups? How?
end
schema.rb:
ActiveRecord::Schema.define(version: 2020_06_22_142356) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "active_storage_attachments", force: :cascade do |t|
t.string "name", null: false
t.string "record_type", null: false
t.bigint "record_id", null: false
t.bigint "blob_id", null: false
t.datetime "created_at", null: false
t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
end
create_table "active_storage_blobs", force: :cascade do |t|
t.string "key", null: false
t.string "filename", null: false
t.string "content_type"
t.text "metadata"
t.bigint "byte_size", null: false
t.string "checksum", null: false
t.datetime "created_at", null: false
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
end
create_table "groups", force: :cascade do |t|
t.string "title"
t.bigint "user_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["user_id"], name: "index_groups_on_user_id"
end
create_table "contactships", force: :cascade do |t|
t.bigint "user_id"
t.bigint "contact_id"
t.integer "status", limit: 2, default: 0
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["contact_id"], name: "index_contactships_on_contact_id"
t.index ["user_id"], name: "index_contactships_on_user_id"
end
create_table "posts", force: :cascade do |t|
t.string "description"
t.integer "user_id"
t.string "thought"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "user_groups", force: :cascade do |t|
t.bigint "user_id", null: false
t.bigint "group_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["group_id"], name: "index_user_groups_on_group_id"
t.index ["user_id"], name: "index_user_groups_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "first_name"
t.string "last_name"
t.string "groupid"
t.text "bio"
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "groups", "users"
add_foreign_key "comments", "users"
add_foreign_key "user_groups", "groups"
add_foreign_key "user_groups", "users"
end
How would I go about developing the method so I can successfully add a contact to a group in the console? I'm confused particularly about the method to make that happen, especially because the contacts are not their own model but part of the user model.
Thanks!
You could do
group = Group.find(params[:id])
contact = User.find(params[:user_id])
UserGroups.create(user: contact, group: group)
Naming
You already mention the term contacts in your question, maybe consider naming your association like this. You can specify a class_name attribute to let Rails know the name of the your model class if it doesn't match the association name.
belongs_to :owner, class_name: "User"
has_many: :user_groups
has_many: :contacts, through: :user_groups, class_name: "User"
validates :title, presence: true
https://guides.rubyonrails.org/association_basics.html#options-for-belongs-to
has_many through vs. has_and_belongs_to
You should think also if you really need the UserGroups model or use a has_and_belongs_to association, see from the Rails guide
The simplest rule of thumb is that you should set up a has_many :through relationship if you need to work with the relationship model as an independent entity. If you don't need to do anything with the relationship model, it may be simpler to set up a has_and_belongs_to_many relationship (though you'll need to remember to create the joining table in the database).
https://guides.rubyonrails.org/association_basics.html#choosing-between-has-many-through-and-has-and-belongs-to-many

Create categories in rails App

I would like to create categories in my app:
I got inspired by this question
But when #RailsGuy says: "Create some categories by categories controller and form (I don't think, I need to tell you that stuff, you are able to do it yourself)"
I felt lost...
How and where do I create my list of categories? dogs, cats, birds...
I saw that it could be done in the console but I will display a different pictures for each categories...
Here is my _form.html.slim
= simple_form_for #tuto do |f|
- if #tuto.errors.any?
#error_explanation
h2 = "#{pluralize(#tuto.errors.count, "error")} prohibited this tuto from being saved:"
ul
- #tuto.errors.full_messages.each do |message|
li = message
= f.hidden_field :user_id, value: current_user.id
= f.input :title
= f.collection_select :category_id, Category.all, :id, :name, {prompt: "Choose Category"}
= f.input :content, as: :text, input_html: { rows: "15" }
= f.button :submit, "Save"
my models:
tuto_model.rb
class Tuto < ActiveRecord::Base
acts_as_votable
belongs_to :user
belongs_to :category
validates :category, presence: true
end
categoty_model.rb
class Category < ActiveRecord::Base
has_many :tutos
end
schema.rb
ActiveRecord::Schema.define(version: 20160920133801) do
create_table "categories", force: :cascade do |t|
t.string "name"
t.text "description"
t.string "image"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "tutos", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "title"
t.text "content"
t.integer "user_id"
t.integer "category_id"
end
add_index "tutos", ["user_id"], name: "index_tutos_on_user_id"
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "first_name"
t.string "last_name"
t.boolean "admin"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
create_table "votes", force: :cascade do |t|
t.integer "votable_id"
t.string "votable_type"
t.integer "voter_id"
t.string "voter_type"
t.boolean "vote_flag"
t.string "vote_scope"
t.integer "vote_weight"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "votes", ["votable_id", "votable_type", "vote_scope"], name: "index_votes_on_votable_id_and_votable_type_and_vote_scope"
add_index "votes", ["voter_id", "voter_type", "vote_scope"], name: "index_votes_on_voter_id_and_voter_type_and_vote_scope"
end
thanks a lot for your help
Have the pictues stored in assets. And in the form/view use a conditional?:
<% if tuto.category == dog %>
<%= image_tag 'dog.jpg' %>
<% end %>
Something like that?
Steve.
The other post says to use the controller and form to create new categories. If you used scaffold to create the model Category, you'll have the new & create action in the controller and a new.html.erb and index.html.erb (or.slim if you're using that).
You can create your categories in there, then select one in your Tuto model.
Make sense?
Steve.

factorygirl create model association NoMethodError: undefined method

When I try to run FactoryGirl.create(:job, :purchased) I get the following error. I have been battling this for a long time now and I believe I have a pluralization issue.
Issue
Models
class Job < ActiveRecord::Base
belongs_to :company
belongs_to :category
has_one :coupon
has_many :payments
end
class Payment < ActiveRecord::Base
belongs_to :job
belongs_to :coupon
end
class Coupon < ActiveRecord::Base
belongs_to :job
end
Factory
FactoryGirl.define do
factory :job do
category
company
title { FFaker::Company.position }
location { "#{FFaker::Address.city}, #{FFaker::AddressUS.state}" }
language_list { [FFaker::Lorem.word] }
short_description { FFaker::Lorem.sentence }
description { FFaker::HTMLIpsum.body }
application_process { "Please email #{FFaker::Internet.email} about the position." }
trait :featured do |job|
job.is_featured true
end
trait :reviewed do |job|
job.reviewed_at { Time.now }
end
trait :purchased do |job|
job.reviewed_at { Time.now }
job.start_at { Time.now }
job.end_at { AppConfig.product['settings']['job_active_for_day_num'].day.from_now }
job.paid_at { Time.now }
association :payment, factory: :payment
end
trait :expired do |job|
start_at = (200..500).to_a.sample.days.ago
job.reviewed_at { start_at }
job.start_at { start_at }
job.end_at { |j| j.start_at + AppConfig.product['settings']['job_active_for_day_num'].days }
job.paid_at { start_at }
# TBD ADD PAYMENT
end
end
end
Partial Schema
create_table "payments", force: :cascade do |t|
t.decimal "price_paid", precision: 8, scale: 2, default: 0.0
t.string "stripe_customer_token"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "jobs", force: :cascade do |t|
t.string "title", limit: 50, null: false
t.string "slug", limit: 250, null: false, index: {name: "index_jobs_on_slug"}
t.string "vanity_url", limit: 250
t.string "location", limit: 100, null: false
t.string "short_description", limit: 250, null: false
t.text "description", null: false
t.text "application_process", null: false
t.boolean "is_featured", default: false
t.datetime "start_at"
t.datetime "end_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "company_id", index: {name: "index_jobs_on_company_id"}, foreign_key: {references: "companies", name: "fk_jobs_company_id", on_update: :no_action, on_delete: :no_action}
t.datetime "deleted_at", index: {name: "index_jobs_on_deleted_at"}
t.integer "category_id", index: {name: "index_jobs_on_category_id"}, foreign_key: {references: "categories", name: "fk_jobs_category_id", on_update: :no_action, on_delete: :no_action}
t.datetime "paid_at"
t.datetime "reviewed_at"
t.integer "payment_id", index: {name: "index_jobs_on_payment_id"}, foreign_key: {references: "payments", name: "fk_jobs_payment_id", on_update: :no_action, on_delete: :no_action}
end
create_table "coupons", force: :cascade do |t|
t.integer "code", limit: 8, null: false, index: {name: "index_coupons_on_code", unique: true}
t.integer "percent_discount", limit: 2, null: false
t.datetime "start_at", null: false
t.datetime "end_at", null: false
t.datetime "executed_at"
t.datetime "deleted_at", index: {name: "index_coupons_on_deleted_at"}
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "job_id", index: {name: "index_coupons_on_job_id"}, foreign_key: {references: "jobs", name: "fk_coupons_job_id", on_update: :no_action, on_delete: :no_action}
t.integer "payment_id", index: {name: "index_coupons_on_payment_id"}, foreign_key: {references: "payments", name: "fk_coupons_payment_id", on_update: :no_action, on_delete: :no_action}
end
Updates per chat below
create_table "jobs", force: :cascade do |t|
t.string "title", limit: 50, null: false
t.string "slug", limit: 250, null: false, index: {name: "index_jobs_on_slug"}
t.string "vanity_url", limit: 250
t.string "location", limit: 100, null: false
t.string "short_description", limit: 250, null: false
t.text "description", null: false
t.text "application_process", null: false
t.boolean "is_featured", default: false
t.datetime "start_at"
t.datetime "end_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "company_id", index: {name: "index_jobs_on_company_id"}, foreign_key: {references: "companies", name: "fk_jobs_company_id", on_update: :no_action, on_delete: :no_action}
t.datetime "deleted_at", index: {name: "index_jobs_on_deleted_at"}
t.integer "category_id", index: {name: "index_jobs_on_category_id"}, foreign_key: {references: "categories", name: "fk_jobs_category_id", on_update: :no_action, on_delete: :no_action}
t.datetime "paid_at"
t.datetime "reviewed_at"
end
create_table "coupons", force: :cascade do |t|
t.integer "code", limit: 8, null: false, index: {name: "index_coupons_on_code", unique: true}
t.integer "percent_discount", limit: 2, null: false
t.datetime "start_at", null: false
t.datetime "end_at", null: false
t.datetime "executed_at"
t.datetime "deleted_at", index: {name: "index_coupons_on_deleted_at"}
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "job_id", index: {name: "index_coupons_on_job_id"}, foreign_key: {references: "jobs", name: "fk_coupons_job_id", on_update: :no_action, on_delete: :no_action}
end
create_table "payments", force: :cascade do |t|
t.decimal "price_paid", precision: 8, scale: 2, default: 0.0
t.string "stripe_customer_token"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "job_id", index: {name: "index_payments_on_job_id"}, foreign_key: {references: "jobs", name: "fk_payments_job_id", on_update: :no_action, on_delete: :no_action}
t.integer "coupon_id", index: {name: "index_payments_on_coupon_id"}, foreign_key: {references: "coupons", name: "fk_payments_coupon_id", on_update: :no_action, on_delete: :no_action}
end
Errors
TRAITS WORKING
trait :purchased do |job|
job.reviewed_at { Time.now }
job.start_at { Time.now }
job.end_at { AppConfig.product['settings']['job_active_for_day_num'].day.from_now }
job.paid_at { Time.now }
payments { |j| [j.association(:payment)] }
end
In your trait your are defining association :payment, factory: :payment
but job has_many payments.
To work, your models should be:
class Job < ActiveRecord::Base
belongs_to :payment
end
class Payment < ActiveRecord::Base
has_many :jobs
end
If you want to keep your model as you have and create a trait with a job containing multiple payments, you need to do something like this:
How to set up factory in FactoryGirl with has_many association

has_many through associations

I'm making an online fashion store. I have a Category Model and a Sizes Model. A model can have many sizes. A Size can have many Categories.
Therefore i am using has_many through association. The category model and sizes model will be linked via a table called category_sizes.
I will create a bunch of sizes like XS, Small, Medium. Then I will create a category Lets say Shirt then i can select all the Sizes a Shirt will have. Then click create.
How do i make the sizes appear in my view? I tried for hours.
Category Model
class Category < ActiveRecord::Base
has_ancestry
has_many :items
validates :name, presence: true, length: { maximum: 20 }
has_many :category_sizes
has_many :sizes, through: :category_sizes
end
Sizes Model
class Size < ActiveRecord::Base
validates :title, presence: true, length: { maximum: 15 }
validates :title, uniqueness: true
has_many :category_sizes
has_many :categories, through: :category_sizes
end
category_size model
class CategorySize < ActiveRecord::Base
belongs_to :category
belongs_to :sizes
end
Here is my form.
<div class="container">
<div class=“row”>
<div class="col-md-6 col-md-offset-3">
<div class="panel panel-primary">
<div class="panel-body">
<%= simple_form_for(#category) do |f| %>
<div class="form-inputs">
<%= f.input :name %>
<%= f.association :category_sizes %>
<%= f.collection_select :parent_id, Category.order(:name), :id, :name, {prompt: "Select Parrent ID If Applicable"},include_blank: true %>
<div class="form-actions"><%= f.button :submit %></div>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>
Schema
ActiveRecord::Schema.define(version: 20150915113019) do
create_table "categories", force: :cascade do |t|
t.string "name"
t.string "ancestry"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "categories", ["ancestry"], name: "index_categories_on_ancestry"
create_table "category_sizes", force: :cascade do |t|
t.integer "category_id"
t.integer "size_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "category_sizes", ["category_id"], name: "index_category_sizes_on_category_id"
add_index "category_sizes", ["size_id"], name: "index_category_sizes_on_size_id"
create_table "items", force: :cascade do |t|
t.string "title"
t.decimal "price"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.integer "category_id"
end
add_index "items", ["user_id", "created_at"], name: "index_items_on_user_id_and_created_at"
add_index "items", ["user_id"], name: "index_items_on_user_id"
create_table "sizes", force: :cascade do |t|
t.text "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "taggings", force: :cascade do |t|
t.integer "tag_id"
t.integer "taggable_id"
t.string "taggable_type"
t.integer "tagger_id"
t.string "tagger_type"
t.string "context", limit: 128
t.datetime "created_at"
end
add_index "taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true
add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context"
create_table "tags", force: :cascade do |t|
t.string "name"
t.integer "taggings_count", default: 0
end
add_index "tags", ["name"], name: "index_tags_on_name", unique: true
create_table "users", force: :cascade do |t|
t.string "username"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.string "remember_digest"
t.boolean "admin", default: false
t.string "activation_digest"
t.boolean "activated", default: false
t.datetime "activated_at"
t.string "reset_digest"
t.string ">"
t.datetime "reset_sent_at"
t.string "avatar_file_name"
t.string "avatar_content_type"
t.integer "avatar_file_size"
t.datetime "avatar_updated_at"
t.text "description"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
end
Did you try something like this?
<%= f.select(:size_id, Size.all.map {|s| [s.title, s.id]}) %>
In your controller define ,
#size_variant_array = #category.sizes
In your view,
<%= select_tag 'size',options_for_select(#size_variant_array.collect{ |pv| [pv.title, pv.id] }) ,:prompt => "Please Select"%>

Resources