sunspot_rails gem - sunspot-rails

Currently I'm migrating search logic to sunspot search engine , I have a query how to implement search in the polymorphic association .
This is the model content
Class Vendor < ActiveRecord::Base
has_and_belongs_to_many :specialties
end
vendor table fields name,toll_free,credit
class Specialty < ActiveRecord::Base
has_and_belongs_to_many :vendors
end
specialty table fields name, created_at, updated_at
how to search with the specialty name and display the result where to add searchable for this association.

I have implemented sunspot search in the model like this
searchable do
autocomplete :vendor_name, :using => :name
text :name,:credit,:toll_free
text :specialties do |vendor|
vendor.specialties.map { |specialty| specialty.name }
end
end
In the controller
#search = Vendor.search(:include=>[:specialties]) do
fulltext params[:search]
paginate :page => params[:page], :per_page => 30
end
#vendors = #search.results
I have followed this site
https://github.com/sunspot/sunspot/wiki/Adding-Sunspot-search-to-Rails-in-5-minutes-or-less
I'm sharing my experience in which I have used sunspot search engine in my project ..

Related

How to create automated association in ruby on rails with mysql

i got 2 tables connected with each other.
device and push information are my models.
class Device < ActiveRecord::Base
has_one :pushinformation
end
class Pushinformation < ActiveRecord::Base
belongs_to :device
end
these are my 2 model files and their relationships.
and these are my migration files
class CreateDevices < ActiveRecord::Migration
def change
create_table :devices do |t|
#t.integer :id
t.string "token"
t.string "carrier"
t.string "segment"
#t.datetime :created_at
#t.datetime :updated_at
t.timestamps
end
end
end
class CreatePushinformations < ActiveRecord::Migration
def change
create_table :pushinformations do |t|
t.integer "device_id"
#t.string "token"
t.string "first_name"
t.string "last_name"
t.string "nickname"
t.timestamps
end
end
end
now the thing is , i was able to create a relationship successfully in rails console by saying
device.pushinformation=push
and they were associated.
How can i make this process automated, like when i add one device- it will have a push information table filled aswell,
i thought about having the same attribute and relating them might be the solution. In this case its token and its completely unique.
How can i create this relationships? I need to be able to know which device has what kind of first_name
i m a beginner in ruby and this is a newbie question sorry guys :)
I am not sure I understand completely what you ask but my guess is that you could use a callback on create
class Pushinformation < ActiveRecord::Base
belongs_to :device
after_create :create_push_notification
private
def create_push_notification
...
end
end
check the docs
http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
xlembouras's answer is right (to a degree), but as you're new, let me explain it for you:
--
Associations
ActiveRecord associations are nothing magical, they're just a way to associate two "objects" using a relational database setup.
ActiveRecord is an ORM -- "object relationship mapper" -- which basically means it just provides a level of abstraction for your ActiveRecord objects to associate with each other
Herein lies the crux of the matter - you need to apprciate how and why your associations will work, and more importantly, how to populate them correctly:
--
Models
Firstly, you need to appreciate the object-orientated nature of Ruby (& by virtue of running on Ruby, Rails). This is where the Models of Rails play such a vital role -- they allow you to build & manage objects from your database
The ActiveRecord associations give you the ability to manage the associations those objects have - maning if you build one, you should be able to build the other:
#app/models/device.rb
Class Device < ActiveRecord::Base
has_one :push_information
before_create :build_push_information #-> creates associative object before creation
end
#app/models/push_information.rb
Class PushInformation < ActiveRecord::Base
belongs_to :device
end
You need to consider the importance of what I've written above.
What you need is to create a push_information object with the same foreign_key as the device object, which can be achieved by using the build method
This will essentially create a "blank" version of your associative object, saving it with the correct foreign key etc
--
Nesting
Further to this, you have to appreciate the idea of "nesting", especially the method accepts_nested_attributes_for
This allows you to create associative / dependent objects based on your "parent" object:
#app/models/device.rb
Class Device < ActiveRecord::Base
has_one :push_information
accepts_nested_attributes_for :push_information
end
#app/models/push_informtion.rb
Class PushInformation < ActiveRecord::Base
belongs_to :device
end
This gives you the ability to do the following:
#app/controllers/devices_controller.rb
Class DevicesController < ApplicationController
def new
#device = Device.new
#device.build_push_information
end
def create
#device = Device.new(device_params)
#device.save
end
private
def device_params
params.require(:device).permit(:your, :device, :params, push_information_attributes: [:push, :information, :attributes])
end
end
This gives you the ability to populate the devices#new form like so:
#app/views/devices/new.html.erb
<%= form_for #device do |f| %>
<%= f.text_field :your_device_attributes %>
<%= f.fields_for :push_information do |p| %>
<%= p.text_field :your_field %>
<% end %>
<%= f.submit %>
<% end %>
Add a create
method to your Devise class. Something like:
def self.create(token, carrier, segment)
device = Device.new(:token => token, :carrier => carrier, :segment => segment)
pi = Pushinformation.create(device.id,..) # other params
end

Storing Location Data in the Database

I need to store data about specific Objects which include information about Location(Country, City, District) of an object. I'm trying to figure out the best way to store described above location data in the MySQL database and how it should look like in the rails active model.
My dummy idea is to create 3 separate tables like below:
Location_countries
id
name
Location_cities
id
country_id
name
Location_districts
id
city_id
name
Create a separate table for an object and call it the item_location and include Ids of object its country... so on
Next is to create 3 Rails models (Country, City, Districts).. , but I think it's a very dirty way and it can be combined into the single Model like Item_location
Any Ideas?
Thank you in advance!
I don't entirely understand what you're looking to do, but either way, here's how I'd tackle it:
#app/models/object.rb
Class Object < ActiveRecord::Base
has_one :location
end
#app/models/location.rb
Class Location < ActiveRecord::Base
belongs_to :object
belongs_to :city
belongs_to :district
delegate :name, to: :city, prefix: true
delegate :name, to: :district, prefix: true
end
#app/models/city.rb
Class City < ActiveRecord::Base
has_many :locations
belongs_to :country
end
#app/models/district.rb
Class District < ActiveRecord::Base
has_many :locations
end
#app/models/country.rb
Class Country < ActiveRecord::Base
has_many :cities
end
This will give you the ability to call:
#object = Object.find params[:id]
#object.location.city_name
#object.location.district_name

Rails MySQL query with Single Table Inheritance N+1 issue

I am trying to find all users that signed up during a given period of time to the ActionMovie plan. I am running into an N+1 problem and it's taking me a very long time to get the number of new signups. I was wondering if there was any creative thing I could do with arel_tables or something like that that could help cut down on this process?
My current code looks similar to the below:
#find all UserMovies created during time frame
user_movies = UserMovie.where(:created_at => start_time..end_time)
#find users
users = user_movies.collect {|um| um.user}
#iterate through each users user_movies and see if the their first action movie was during the time frame I am looking for
users.each do |user|
user_movies_array = user.user_movies.map {|um| {um.movie.type => um.created_at}}
user_movies_array.each do |um|
if um["ActionMovie"] > start_time
puts "new user"
end
end
end
Class User
has_many :user_movies
has_many :movies, :through => :user_movies
end
Class Movie
has_many :user_movies, :foreign_key => :movie_id
has_many :users, :through => :user_movies
end
Class UserMovie
belongs_to :user
belongs_to :movie
end
Class ActionMovie < Movies
end
Class SuspenseMovie < Movies
end
Have you tried eager loading the Movie association using the :include option?
Take a look at the API docs for #has_many to see specific implementation and scroll to the top to the section called Eager loading of associations to see a general overview.

Rails activerecord order by field in related table

I have a typical forum style app. There is a Topics model which has_many Posts.
What I want to do using Rails 2.3.x is query the topics table and sort by the most recent post in that topic.
#topics = Topic.paginate :page => params[:page], :per_page => 25,
:include => :posts, :order => 'HELP'
I'm sure this is a simple one but no joy with Google. Thanks.
Sorting on a joined column is probably a bad idea and will take an enormous amount of time to run in many situations. What would be better is to twiddle a special date field on the Topic model when a new Post is created:
class Post < ActiveRecord::Base
after_create :update_topic_activity_at
protected
def update_topic_activity_at
Topic.update_all({ :activity_at => Time.now }, { :id => self.topic_id})
end
end
Then you can easily sort on the activity_at column as required.
When adding this column you can always populate the initial activity_at with the highest posting time if you have existing data to migrate.

Use :include statement to find records

I'm working on Ruby On Rails 2.3.2 and I'm learning how to use the :include statement.
I'd like to get all the announcements order by their rate. I've got two models and tables for that: Announcement and Rate.
The models look like this:
class Announcement <
ActiveRecord::Base
belongs_to :rate
end
class Rate < ActiveRecord::Base
belongs_to :announcement
end
I'd like to do something like the following, but using :include statement.
Announcement.find_by_sql 'select * from announcements ann inner join rates r on ann.id = r.announcement_id order by r.average DESC'
I already tried this:
Announcement.paginate :page => params[:page], :per_page => 10, :include => [:rates], :order => 'rates.average DESC'
but it's trying to associate rates.id = announcements.id, instead of rates.announcement_id = announcement_id
How can I specify the correct relationship to make this work?
As Yuri points out in the comments, you have incorrectly defined your relationship.
Announcements should have_one :rate
As a named scope on announcment:
class Announcement < ActiveRecord::Base
has_one :rate
named_scope :order_by_rate, :include => :rate, :order => 'rates.average DESC'
end
Announcement.order_by_rate.paginate :per_page => 10, :page => params[:page]
Note the difference between :include and :joins as a find option. :joins will join the on the association(s) or SQL JOIN fragment given for purposes of complex WHERE/ORDER clauses. :include will only works on associations, it provides the same advantages of :joins, and also eager load the association.
Where eager loading makes a difference:
With include, #a.rate is populated in the same SQL statement that populates #a.
#a = Association.first :include => :rate
Without include #a.rate is not populated until required.
#a = Association.first
#a.rate #=> #a.rate is populated here, with a separate SQL statement.