Reindex just one particular record with sunspot - ruby-on-rails

I have two models
class User < ActiveRecord::Base
has_many :posts
searchable do
text :post_titles
end
def post_titles
posts.map &:title
end
end
class Post < ActiveRecord::Base
belongs_to :user
end
the problem is that when I update title of the Post sunspot doesn't update index for related user and it is not searchable by new data. If I do User.index it solves problem but takes too much time. Are there any better solutions to update parent record index on child record change(like reindex just parent record and not all users)?

Sunspot provides an instance index() method, for indexing one record.
What I did was
class Post
belongs_to :user
after_save :update_user_index
private
def update_user_index
user.index
end
end
If you are running this in console, and want to see results immediately, call Sunspot.commit

Related

Rails 4.1 nested model form fields

Booking -< Orders -< Transactions
class Booking < ActiveRecord::Base
has_many :orders
end
class Order < ActiveRecord::Base
belongs_to :booking
has_many :transactions
end
class Transaction < ActiveRecord::Base
belongs_to :order
end
I need to be able to create a Transaction without an Order or Booking existing.
I'm trying to achieve the following:
When a Transaction is created an Order and a Booking is automatically created. The transaction form can take a Booking.booking_number which will be saved to the above automatically created Booking.
I'm very new to rails and have tried a combination of accepts_nested_attributes_for, Ryan Bates' nested model form part1 screencast and form_fields_for without success.
Some guidance, not necessarily code, would be much appreciated.
My routes look like:
I need to be able to create a Transaction without an Order or Booking
existing.
Bad system design - surely a transaction would follow an order or booking?
From your question, I'd highly recommend creating a booking or order first. This will allow you to create a transaction as a bolt-on to the order or booking:
#app/controllers/bookings_controller.rb
Class BookingsController < ApplicationController
def create
booking = Booking.new(booking_params)
booking.save
end
end
#app/models/booking.rb
Class Booking < ActiveRecord::Base
before_create :build_transaction #-> creates a blank transaction which can be populated later
end
Nonetheless, there's nothing stopping you creating a transaction & assigning an order later
You can do this:
#app/controllers/transactions_controller.rb
def create
Transaction.new(transaction_params)
end
#app/models/transaction.rb
Class Transaction < ActiveRecord::Base
after_create :order
def order
self.order.create!([order_details?])
end
end
If you tell me some more about what you're building, I'll be able to create a more refined response!
Try this it may be work.
In your model
accepts_nested_attributes_for :order, :allow_destroy => true
change whether true/false depending on your form

How to update a collection after parent is destroyed?

I'm developing a Rails 3.2.13 application and I have two models:
class Invoice < ActiveRecord::Base
has_many :client_invoices, dependent: :nullify
...
end
class ClientInvoice < ActiveRecord::Base
belongs_to :invoice
...
end
I was wondering if there is a way to make the ClientInvoices to know when their parent Invoice is been destroyed and call a private method to update their status.
I've tried to perform this in the after_destroy callback of the Invoice, by looping the collection and changing the status of each ClientInvoice, but the collection is already empty there.
What is the best way to achieve this?
Thank you very much in advance!
before_destroy will work.
before_destroy :update_client_invoice_statue
private
def update_client_invoice_statue
client_invoices.each do |invoice|
#... code to update the status of record
end
end
Note : This before_destroy method should return true for proceeding the destruction of the object.

Complex After save association in ruby on rails

Theory :- after create of a record in customer bill, i am sending two sets of data two different models. one set of data is sent to ledger and one set of data is sent to ledger_line_item. the complexity is that after sending of data i want the ledger_id to be stored in ledger_line_item. the code is as follows
code :-
class CustomerBill < ActiveRecord::Base
after_create :creating_ledger_line_items, :creating_ledger_items
def creating_ledger_items
CustomerLedger.create(:customer_id =>self.customer_id,/*rest of attributes*/)
end
def creating_ledger_line_items
CustomerLedgerLineItem.create(:customer_id =>self.customer_id,/*rest of attributes*/)
end
end
in ledger i have written
class CustomerLedger < ActiveRecord::Base
after_save :update_record_line_items
def update_record_line_items
a = CustomerLedgerLineItem.find_by_customer_id(self.customer_id)
a.update_attributes(:customer_ledger_id => self.id)
end
end
the above code works fine without error but the ledger_id is not been posted in ledger_line_items. i am not able to determine why this error is happening? is there any other way i can achieve my goal of posting ledger_id in ledger_line_items after a bill is created?
Guidance Required. Thanking you in advance.
You can change your models something as follows.:
I am assuming you have Customer Model.
class Customer < ActiveRecord::Base
has_one :customer_ledger
has_many :customer_ledger_line_items, :through => :customer_ledger
accepts_nested_attributes_for :customer_ledger
end
class CustomerLedger < ActiveRecord::Base
has_many :customer_ledger_line_items
accepts_nested_attributes_for :customer_ledger_line_items
end
class CustomerBill < ActiveRecord::Base
belongs_to :customer
after_create :creating_ledger_items, :creating_ledger_line_items
def creating_ledger_line_items
cl = self.customer.customer_ledger.build(your_attributes)
cl.save!
end
def creating_ledger_items
cli = self.customer.customer_ledger.customer_ledger_items.build(your_attributes)
cli.save!
end
end
In case you want to create the models on an *after_create* hook, I'll explain what's the problem.
When you create a model in rails, and you have hooks like *after_create*, *before_update*, etc. all the updates happens in a Transaction, so if any of them throws an exception, nothing is updated.
In this case, within a Transaction, you are trying to get the ID of a CustomerLedger that doesn't exists yet, because since everything is within a Transaction, the record is not saved to the database until the transaction is executed, and thats the reason that on CustomerLedger#update_record_line_items, self.id is always nil.
Using the nested attributes proposed by codeit is probably the best solution to your problem, but if you feel that nested attributes its an advance topic, you can do something like:
class CustomerBill < ActiveRecord::Base
after_create :created_leder_data
def create_ledger_data
customer_ledger = CustomerLedger.build(customer_id: self.customer_id, # Rest of attributes)
customer_ledger.customer_ledger_line_items.build(customer_id: self.customer_id, # Rest of attributes)
customer_ledger.save!
end
end

rails memcached dalli Marshalling error for key

I have such action in my controller:
def my
#user = Ads::User.find current_user.id
#postings = Rails.cache.fetch("#user.postings.includes(:category)") do
#postings = #user.postings.includes(:category)
end
end
I'm trying to cache #postings and get such error:
Marshalling error for key '#user.postings.includes(:category)': can't dump anonymous class #<Module:0x000000048f9040>
You are trying to cache a Ruby object which cannot be serialized to memcached.
If I try to cache #postings without includes there are no errors.
Can't figure out what is the problem.
You can find relevant models in the bottom:
module Ads
class User < ::User
has_many :postings, dependent: :destroy
end
end
module Ads
class Posting < ActiveRecord::Base
belongs_to :user, counter_cache: true
belongs_to :category
end
end
module Ads
class Category < ActiveRecord::Base
has_many :postings, dependent: :destroy
end
end
The cache fetch code is all wrong. The parameter to fetch is a string that identifies the data you want. Your code is trying to use the same string for every user, so they would all see the same postings that would be saved by the first call of this method.
In my example below I used the user id and a string 'postings' to indicate all postings for a specific user.
It is incorrect to assign #postings inside the fetch block, the result of the block (the query result) is saved to #postings
Finally, ActiveRecord delays making the actual database call until absolutely necessary. The .all call at the end of the query will return the data, and the data is what you want cached, not the configuration data used to create a query.
Here is the correct code:
#postings = Rails.cache.fetch("#{#user.id}:postings") do
#user.postings.includes(:category).all
end
It's likely complaining about this:
class User < ::User
Is there any reason why you're not using:
class User < ActiveRecord::Base

Set default random column value in ActiveRecord model

got 2 models:
class User < ActiveRecord::Base
has_many :posts
end
and
class Post < ActiveRecord::Base
belongs_to :user
end
the Posts table has a column: u_hash. This is supposed to be a randomly generated identifying hash (for public viewing). What is the best way to generate this hash and how can I add it to the table? The idea is that all this will happen in the background and not be visible to the user (no hidden field in the form). The database used is MySQL if that could help me out somehow.
Thanks in advance!
J
You most likely need before_validation_on_create callback for your Post model. This callback is internally called by ActiveRecord functionality when you save a new Post record into database.
A good callback reference and a hint of the order callbacks are called in you can find here.
Here's a code, that explains why it is before_validation_on_create that you need to use:
class Post < ActiveRecord::Base
belongs_to :user
validates_uniqueness_of :u_hash
before_validation_on_create :generate_u_hash
def generate_u_hash
begin
new_u_hash = "random hash here"
end while Post.find_by_u_hash(new_u_hash)
self.u_hash = new_u_hash
end
end
This sounds like a job for ActiveRecord callbacks.
If your posts tables has a before_create callback, you can create and set a value automatically every time a new post instance is created.
e.g.:
class Post < ActiveRecord::Base
belongs_to :user
before_create :set_uhash_column
private
def set_uhash_column
#your code here - something like self.uhash = ...
end
end

Resources