thinking-sphinx (3.3.0)
Rails 5.0.4
I have troubles with updating associations - ThinkingSphinx (apparently) does not reindex them.
model1
class DocRequest < ApplicationRecord
has_many :doc_responses, :inverse_of => :doc_request, dependent: :destroy
end
model2
class DocResponse < ApplicationRecord
belongs_to :doc_request, :inverse_of => :doc_responses
end
app/indices/doc_response_index.rb
ThinkingSphinx::Index.define :doc_response, :with => :active_record, :delta => true do
indexes doc_request.title, :as => :doc_request_title, :sortable => true
indexes text
has doc_request_id
end
Controller:
result = DocResponse.search #keyword
When I update the title of a DocRequest model (in Admin area), ThinkingSphinx obviously does not reindex the doc_request.title field, e.g. the result = DocResponse.search #keyword query doesn't change.
What's wrong?
Running rake ts:rebuild solves the problem. But I can't do it on every update.
I tried to add a
ThinkingSphinx::Index.define :doc_request, :with => :active_record, :delta => true do
indexes title
end
index and then to perform directly result = DocRequest.search #keyword - it worked correctly. But that's surely not what I need.
db/schema.rb
create_table "doc_requests", force: :cascade do |t|
t.string "title"
t.text "text"
t.boolean "paid"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "delta", default: true, null: false
t.index ["user_id"], name: "index_doc_requests_on_user_id", using: :btree
end
create_table "doc_responses", force: :cascade do |t|
t.boolean "chosen"
t.text "text"
t.float "price"
t.integer "user_id"
t.integer "doc_request_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "delta", default: true, null: false
t.index ["doc_request_id"], name: "index_doc_responses_on_doc_request_id", using: :btree
t.index ["user_id"], name: "index_doc_responses_on_user_id", using: :btree
end
What did I do wrong? I need some help.
Can I enable some verbose console mode in ThinkingSphinx - to see the reindexing events while updating? That might be useful for debugging.
I quess that the answer is somewhere near this http://freelancing-gods.com/thinking-sphinx/deltas.html#deltas-and-associations , but what exactly to do - I don't know.
Thinking Sphinx does not automatically detect your associations and how they relate to your indexed data whenever you make an update to your models, as that could potentially be very complex (and thus, slow).
You've linked to the exactly correct part of the documentation, though it's slightly out of date - you'll want to use after_commit instead. Whenever you have a DocRequest updating, you'll want to set the delta flags for all of the associated DocResponse objects:
class DocRequest < ActiveRecord::Base
# ...
after_commit :set_response_delta_flags
# ...
private
def set_response_delta_flags
doc_responses.each { |response|
response.update_attributes :delta => true
}
end
# ...
end
Updating each response will fire off the delta processing for the affected response objects, which will in turn ensure their Sphinx data is up-to-date.
Related
So I am currently assigned a task in Ruby which I have never used before and I've run into a very strange problem. I have this migration for a model message, which has an index on chat_id and number.
class CreateMessages < ActiveRecord::Migration[5.2]
def change
create_table :messages do |t|
t.references :chat, foreign_key: true, null: false
t.integer :number, null: false
t.string :body
#t.index [:chat_id, :number] doesn't work
t.timestamps
end
#add_index :messages, [:chat_id, :number] #doesn't work either
end
end
The end schema of both those migrations when running rails db:migrate is this
create_table "messages", force: :cascade do |t|
t.integer "chat_id", null: false
t.integer "number", null: false
t.string "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["chat_id", "number"], name: "index_messages_on_chat_id_and_number"
t.index ["chat_id"], name: "index_messages_on_chat_id"
end
Obviously, the second created index is completely useless. How do I prevent this from occuring and create only one index when migrating?
Ruby 2.7.6
Rails 5.2.8.1
This line is adding the index you wish to remove. It accepts an index parameter which defaults to true, change it to:
t.references :chat, foreign_key: true, null: false, index: false
This question was discussed numerous times, however I run into an issue that I could not find an answer to.
I am building a login system where one Member(:class) "bails for" a new Member. Internally, they are referenced as "member" and "candidate" respectively. Until the member has accepted the bail, a BailRequest(:class) is listed in the according table.
According to the rails guide, the right way to tell rails about the class refering to would be
class BailRequest < ApplicationRecord
belongs_to :candidate, class_name: "Member"
belongs_to :member
end
where class_name: "Member" should tell rails that BailRequest.candidate is of class: Member. The very same approach worked in the member class flawlessly
class Member < ApplicationRecord
belongs_to :bail, class_name: "Member", optional: true
has_many :associates, class_name: "Member", foreign_key: "bail_id"
end
However, this time when I want to save a BailRequest to the database, I get an ActiveRecord::StatementInvalid: SQLite3::SQLException: no such table: main.candidates.
It looks like ActiveRecord is expecting a table called "candidates" here. What am I missing?
$ rails -v
Rails 5.2.1
[$ ruby -v
ruby 2.3.1p112 (2016-04-26) [i386-linux-gnu]]
The schema.rb shows the following after migration
create_table "bail_requests", force: :cascade do |t|
t.integer "candidate_id"
t.integer "member_id"
t.string "message", limit: 100
t.boolean "accepted"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["candidate_id"], name: "index_bail_requests_on_candidate_id", unique: true
t.index ["member_id"], name: "index_bail_requests_on_member_id"
end
create_table "members", force: :cascade do |t|
t.string "email", limit: 50, null: false
t.string "password_digest", null: false
t.integer "bail_id"
t.string "username", limit: 50
t.string "first_name", limit: 50
t.string "last_name", limit: 50
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_members_on_email", unique: true
t.index ["username"], name: "index_members_on_username", unique: true
end
Logic:
When a Member m registers, m has to reference a Member n by name.
m.bail equals nil/null and a BailRequest br is created with
br.member = n and br.candidate = m
If member accepts the bail, br.accepted is set to true. m.bail is set to n and m is in n.associates
In the migration file, I changed
t.references :candidate, index: {:unique=>true}
to
t.integer :candidate_id, index: {:unique=>true}, foreign_key: true
and rerun the migration. It is now working on the rails console. Thanks to arieljuod for your effort.
I am really stuck with dealing with querys from multiple tables in rails. If this is my controller:
def show
#user = User.find(params[:id])
#entry = Entry.joins(:event, :user).where(users: { id: '2' })
#event = Event.find(1)
end
and this is my models
class Entry < ApplicationRecord
belongs_to :user
belongs_to :event
class User < ApplicationRecord
has_many :entries, dependent: :destroy
class Event < ApplicationRecord
has_many :entries, dependent: :destroy
The query runs happily in rails console and returns the records but I don't know how to access specific units like entry.course in my embeded ruby.
Update
To clarify On a page I woulk like to output somthing for all the entries assosiated with the user logged in to the page.
eventName eventLocation eventDate course siCard
The schema:
ActiveRecord::Schema.define(version: 20171204183458) do
# These are extensions that must be enabled in order to support this
database
enable_extension "plpgsql"
create_table "entries", force: :cascade do |t|
t.string "course"
t.string "siCard"
t.bigint "user_id"
t.bigint "event_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["event_id"], name: "index_entries_on_event_id"
t.index ["user_id", "created_at"], name:
"index_entries_on_user_id_and_created_at"
t.index ["user_id"], name: "index_entries_on_user_id"
end
create_table "events", force: :cascade do |t|
t.string "eventName"
t.string "location"
t.date "eventDate"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "eventLink"
t.string "eventCoordinates"
t.index ["eventName"], name: "index_events_on_eventName", unique: true
end
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.string "firstName"
t.string "remember_digest"
t.boolean "admin"
t.index ["email"], name: "index_users_on_email", unique: true
end
add_foreign_key "entries", "events"
add_foreign_key "entries", "users"
end
You can find it in 2 ways
1)
#entries = Entry.includes(:user,:event).where(user: { id: (params[:id]) })
2)
#entries = User.includes(entries: :event).find(params[:id]).entries
Than in the loop of entries you can access value course of particular entry
e.g.
#entries.each do |entry|
puts "#{entry.course}"
puts "#{entry.event&.name}"
end
Why are you using such a complicated query with joins? If you are looking for the Entrys of #user just use #user.entries. ActiveRecord knows from the has_many how to deal with that.
If you posted a simplified example, you should try to find your Entry with something like .where(user_id: user.id) as long as id is the foreign key. With that you don't need that join, too.
You could confine with one query using
eager_load
def show
#user = User.eager_load(:entries => [:event]).where(users: {id: params[:id]})
end
According to your models you can access entries though user.
#user.entries
#user.entries.map{|entry| entry.course}
Also you can access event (which belongs to entry) though entry.
#user.entries[1].event
#user.entries.map{|entry| entry.event}
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
rails not null / unique in migrations doesn't trigger error :S
class CreateDeditProjects < ActiveRecord::Migration
def change
create_table :dedit_projects do |t|
t.string :name, :null => false
t.string :uid, :unique => true
t.boolean :status
t.timestamps null: false
end
end
end
empty name doesn't trigger error. Neither does duplication of uid.
This is what I see in schema.db
ActiveRecord::Schema.define(version: 20150410105216) do
create_table "dedit_projects", force: :cascade do |t|
t.string "name", null: false
t.string "uid"
t.boolean "status"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
hm, I need to add indexes somewhere I guess? Shouldn't that be automatic?
Not null problem is bogus though.
Rails automatically adds index on id and references and maybe on some other types. If You want to add new index, You can create a migration:
def change
add_index :dedit_projects, :uid, unique: true
end
You can also use validations validates_uniqueness_of and validates_presence_of in models. Although I don't understand why doesn't it work as it is :)
Uniqueness is a property of the index so you need either a separate call to add_index or write it like so
create_table :dedit_projects do |t|
t.string :uid, index: {unique: true}
...
end