Rails associations with search - ruby-on-rails

I have issue with associations with search
class Manufacturer < ApplicationRecord
has_many :translations, class_name: 'ManufacturerTranslation', dependent: :destroy
def self.search(query)
q = query.to_s.parameterize.gsub('-',' ').split
joins(:translations).where("lower(name) LIKE ?", "%#{q}%")
end
and
class ManufacturerTranslation < ApplicationRecord
belongs_to :manufacturer
end
so when i have tried to do search and call translations on it
Manufacturer.search('fra').last.translations
it gives me only translations with name which include fra, not all of translations
so i have 6 translations in total for this manufacturer
but after search a get only 2
database schema
create_table "manufacturer_translations" do |t|
t.integer "manufacturer_id"
t.string "locale"
t.string "name"
t.string "image_source_url"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["manufacturer_id"], name: "index_manufacturer_translations_on_manufacturer_id"
t.index ["name"], name: "index_manufacturer_translations_on_name"
end
create_table "manufacturers", do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "deleted", default: false
end

As you are splitting the string you have to loop through all the entities to search them. And you also have to downcase the results. try out the following code:
def self.search(query)
q = query.to_s.parameterize.gsub('-',' ').split
conditions = ''
q.each do |qu|
conditions = "#{conditions} OR " if conditions.present?
conditions = "#{condidtions} lower(manufacturers.name) LIKE %#{qu.downcase}%"
end
joins(:translations).where(conditions)
end

Assuming you follow Rails conventions I'd suggest you to replace this
joins(:translations).where("lower(name) LIKE ?", "%#{q}%")
with
joins(:translations).where("lower(manufacturers.name) LIKE ?", "%#{q}%")
May be needed to play with quotations

Related

Why is my Rails activerecord many-to-many through relationship not working

Three models Professor, Expertise & ExpertisesProfessor (the join table). I would like to use a has_many activerecord structure but when I call Expertise.professors.all I get an error
*NoMethodError (undefined method `professors' for Class:0x000000000a1ddda0) *
I want to be able to call Expertise.professors and Professor.expertise ???
I am comfortable with using HABTM instead of "has_many through" but for my project I prefer to use the the " has_many through " relationship so please if I could get solutions along those lines only if possible .
**professor.rb**
class Professor < ApplicationRecord
has_many :expertise_professors
has_many :expertises, through: :expertise_professors
end
**expertise.rb**
class Expertise < ApplicationRecord
has_many :expertise_professors
has_many :professors, through: :expertise_professors
end
**expertises_professor.rb**
class ExpertisesProfessor < ApplicationRecord
belongs_to :expertise
belongs_to :professor
end
My Schema File
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2019_12_18_191008) do
create_table "expertises", force: :cascade do |t|
t.string "name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "expertises_professors", id: false, force: :cascade do |t|
t.integer "expertise_id", null: false
t.integer "professor_id", null: false
end
create_table "professors", force: :cascade do |t|
t.string "name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
end
Any ideas what I have missed ?
You can not call Expertise.professors. You first need to load the single record or object of the Expertise like
expertise = Expertise.first
And then you can get all professors
expertise.professiors.all
Same way you can get all expertises for specific professor.

Rails InvalidForeignKey

I am developing a portfolio for my website, I decided to add skills to each portfolio item.
class PortfolioSkill < ApplicationRecord
belongs_to :portfolio
belongs_to :skill
end
class Portfolio < ApplicationRecord
has_many :portfolio_skills
has_many :skills, through: :portfolio_skills
def all_tags=(names)
self.skills = names.split(",").map do |name|
Skill.where(name: name.strip).first_or_create!
end
end
def all_tags
self.skills.map(&:name).join(", ")
end
def remove_skill_tags
PortfolioSkill.where(portfolio_id: id).destroy_all
end
end
create_table "portfolio_skills", force: :cascade do |t|
t.integer "portfolio_id"
t.integer "skill_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["portfolio_id"], name: "index_portfolio_skills_on_portfolio_id"
t.index ["skill_id"], name: "index_portfolio_skills_on_skill_id"
end
create_table "portfolios", force: :cascade do |t|
t.string "name"
t.string "client"
t.date "completed"
t.text "about"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "long_landscape"
t.string "cover"
t.integer "category_id"
t.index ["category_id"], name: "index_portfolios_on_category_id"
end
When I click destroy on the index page I get the
SQLite3::ConstraintException: FOREIGN KEY constraint failed: DELETE FROM "portfolios" WHERE "portfolios"."id" = ?
error. All the associations look right. I used this same pattern for my tags on other models and it worked with no issues. Any help would be great.
You are deleting from portfolios table, but table portfolio_skills has a column referencing it as foreign key. Hence the error.
Trying to delete a parent without checking and deleting its associated children can lead to data inconsistency. This exception is in place to prevent that.
Rails dependent destroy will take care of removing associated children rows while removing a parent.
Try using a dependent destroy:-
class Portfolio < ApplicationRecord
has_many :portfolio_skills, :dependent => :destroy
...
end

Test in Rails console model associations?

Hello I do have this two models and I would like to check that my model associations are working the way it should trough rails console.
I am not able to do the association work. The relationship is the following:
One Event has one rule and one rule belongs to one event. It could not be a rule without an event and it could not be a event without a rule.
Any idea how to test this with rails console?
MODEL 1:
class Event < ActiveRecord::Base
has_and_belongs_to_many :users
has_one :rule
has_many :grand_prixes
belongs_to :eventable, polymorphic: :true
end
MODEL 2
class Rule < ActiveRecord::Base
belongs_to :events
end
Rules' Schema:
create_table "rules", force: :cascade do |t|
t.boolean "abs"
t.boolean "tc"
t.boolean "allow_auto_clutch"
t.boolean "allow_sc"
t.boolean "allow_throttle_blip"
t.boolean "dynamic_track"
t.integer "damage_mult"
t.integer "fuel_rate"
t.integer "tyre_wear_rate"
t.integer "quali_percentage"
t.integer "min_valid_laps"
t.integer "event_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "rules", ["event_id"], name: "index_rules_on_event_id"
Events' Schema:
create_table "events", force: :cascade do |t|
t.string "event_type"
t.string "name", null: false
t.datetime "starting_date"
t.datetime "ending_date"
t.integer "eventable_id"
t.string "eventable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "events", ["eventable_type", "eventable_id"], name: "index_events_on_eventable_type_and_eventable_id"
Thanks in advance.
I think your belongs_to :events should be singular to follow the rails convention :
class Rule < ActiveRecord::Base
belongs_to :event
end
The conventional name of a relation is always singular for belongs_to and has_one, and always plural for has_many.
Related documentation : http://guides.rubyonrails.org/association_basics.html#belongs-to-association-reference
EDIT : There much left to say
You wrote :
ev = Event.create(:name "test1").save
rule = Rule.create.save
create is already a new followed by a save. No need to save afterwards.
the syntax key: value is something very common in ruby, and should be well understood : you're actually writing a hash, equivalent to {:key => value}, but the syntax allows you to write key: value ONLY IF your key is a Symbol.
the columns eventable_type and eventable_id should be in the table rules, who is hosting the polymorphic relation with eventable things. Event should not have these columns, and event_id should not exist at all in rules.
Here's an example of what you can write in your console to create an Event and a Rule :
ev = Event.create(name: "test1")
rule = Rule.create(abs: true, event: ev)
Change your code:
class Rule < ActiveRecord::Base
belongs_to :event
end
With belongs_to you should use singular like event not events.
In console you can check association like:
Event.first.rule if Event.first.present?
For more details you should go through http://guides.rubyonrails.org/association_basics.html documentation.
Current code:
class Rule < ActiveRecord::Base
belongs_to :event
end
class Event < ActiveRecord::Base
has_and_belongs_to_many :users
has_one :rule
has_many :grand_prixes
belongs_to :eventable, polymorphic: :true
end
SCHEMA:
create_table "rules", force: :cascade do |t|
t.boolean "abs"
t.boolean "tc"
t.boolean "allow_auto_clutch"
t.boolean "allow_sc"
t.boolean "allow_throttle_blip"
t.boolean "dynamic_track"
t.integer "damage_mult"
t.integer "fuel_rate"
t.integer "tyre_wear_rate"
t.integer "quali_percentage"
t.integer "min_valid_laps"
t.integer "event_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "rules", ["event_id"], name: "index_rules_on_event_id", unique: true
create_table "events", force: :cascade do |t|
t.string "event_type"
t.string "name", null: false
t.datetime "starting_date"
t.datetime "ending_date"
t.integer "eventable_id"
t.string "eventable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "events", ["eventable_type", "eventable_id"], name: "index_events_on_eventable_type_and_eventable_id"
Tested on console:
ev = Event.create(:name "test1").save
rule = Rule.create.save
No idea how to link it both through console.

All Rails active record foreign keys are nil after import via activerecord-import gem

Ruby 2.3.0, Rails 4.2.4, PostgreSQL 9.5
UPDATE: added activerecord-import code below.
Does anyone know how to make these associations hold, so that a model's table attributes can be referenced in another view? Similar to another Q&A (Rails has_many through aliasing with source and source_type for multiple types), where I have investors, companies, and transactions.
I've tried associations like the below (has_many ... through ...), but I'm failing to get ActiveRecord to recognize the connection among the 3 models & tables. Seeding the db:
The way data gets into these tables is via a csv file having 3 columns. I use roo-xls to extract each into an array of arrays.
My activerecord-import gem-based code (each *_val is an array of 1000s of arrays):
icol = [:name]
ccol = [:name]
tcol = [:investor_name, :company_name, :percent_owned]
investor_val = [["i1"],["i2"]] # just showing 2 arrays for brevity
company_val = [["c1"],["c2"]] # ""
transaction_val = [["i1","c1","pct1"],["i2","c2","pct2"]] # ""
Investor.import icol, investor_val, :validate => false
Company.import ccol, company_val, :validate => false
Transaction.import tcol, transaction_val, :validate => false
Import works, but when I check the transactions table, both company_id and investor_id are nil after executing the activerecord-import .import. I of course would like them to contain the foreign keys for the company and investor model records.
My models are below.
Class Company < ActiveRecord::Base
has_many :investors,
:through => :transactions
has_many :transactions
end
Class Investor < ActiveRecord::Base
has_many :companies,
:through => :transactions
has_many :transactions
end
Class Transaction < ActiveRecord::Base
belongs_to :company
belongs_to :investor
end
Transactions migration (others left out for brevity)
class CreatePositions < ActiveRecord::Migration
def change
create_table :positions do |t|
t.string :investor_name
t.string :company_name
t.string :percent_owned
t.belongs_to :company, index: true
t.belongs_to :manager, index: true
t.timestamps null: false
end
end
end
My schema, where I've added references to the belongs_to (transactions) table.
ActiveRecord::Schema.define(version: 20160128224843) do
create_table "companies", force: :cascade do |t|
t.string "name"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "investors", force: :cascade do |t|
t.string "name"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "transactions", force: :cascade do |t|
t.string "investor_name"
t.string "company_name"
t.float "percent_owned"
t.integer "investor_id"
t.integer "company_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "transactions", ["investor_id"], name: "index_transactions_on_investor_id", using: :btree
add_index "transactions", ["company_id"], name: "index_transactions_on_company_id", using: :btree

Passing database querying tests using spec?

I am learning rspec and databases and have one movie database with the following schema. I'd like to know how to get this test to pass since my efforts seem to be futile. If you need any additional info please let me know in case I'm leaving something vital out that would be helpful:
Schema
create_table "movies", force: true do |t|
t.string "title", null: false
t.integer "year", null: false
t.text "synopsis"
t.integer "rating"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "genre_id", null: false
t.in
end
create_table "genres", force: true do |t|
t.string "name", null: false
t.datetime "created_at"
t.datetime "updated_at"
end
Model setup:
class Movie < ActiveRecord::Base
validates_presence_of :title
validates_presence_of :year
validates_presence_of :genre
has_many :cast_members
has_many :actors, through: :cast_members
belongs_to :genre
belongs_to :studio
Rspec test:
it "partially matches movie titles" do
results = Movie.search('Manhat')
expect(results.count).to eq(2)
expect(results.include?(manhattan)).to be_true
expect(results.include?(mystery)).to be_true
end
Rspec test argument input:
.create(:movie, title: "Manhattan Murder Mystery"
Code I've tried several variations of so far:
class Movie < ActiveRecord::Base
etc, above..
def self.search(query)
select('title').where('title ilike ? OR synopsis ilike ?','%query%', '%query%')
end
You are not passing the parameter to the query. You are always searching for results containing "query". What you should do is:
select('title').where('title ilike ? OR synopsis ilike ?',"%#{query}%", "%#{query}%")
This will substitute the "#{query}" with the parameter passed to the search method.

Resources