Multiple SQL statements for a single array of hash insert - ruby-on-rails

I am doing something like this to insert multiple records at the same time in my rails app.
VoteRecord.create(
[
{ :prospect_id => prospect.id, :state => "OH", :election_type => "GE" },
{ :prospect_id => prospect.id, :state => "OH", :election_type => "PR" }
...
]
)
When I check the log i see that the insert query is fired multiple times by sql. Is it possible to do this in a single query?

You can try active record import for bulk import,checkout wiki and example page.

I haven't used it myself, but you should check out the activerecord-import project (for Rails 3)
github More on this can be found here: wiki

Related

Sort Elasticsearch results by integer value via Searchkick

I'm working on a Rails application that uses Searchkick as an interface to Elasticsearch. Site search is working just fine, but I'm running into an unexpected issue on a page where I'm attempting to retrieve the most recent recoreds from Searchkick across a couple different models. The goal is a reverse chronological list of this recent activity, with the two object types intermingled.
I'm using the following code:
models = [ Post, Project ]
includes = {
Post => [ :account => [ :profile ] ],
Project => [ :account => [ :profile ] ],
}
#results = Searchkick.search('*',
:models => models,
:model_includes => includes,
:order => { :id => :desc },
:limit => 27,
)
For the purposes of getting the backend working, the page in development is currently just displaying the title, record type (class name), and ID, like this:
<%= "#{result.title} (#{result.class} #{result.id})" %>
Which will output this:
Greetings from Tennessee! (Post 999)
This generally seems to be working fine, except that ES is returning the results sorted by ID as strings, not integers. I tested by setting the results limit to 1000 and found that with tables containing ~7,000 records, 999 is considered highest, while 6905 comes after 691 in the list.
Looking through the Elasticsearch documentation, I do see mention of sorting numeric fields but I'm unable to figure out how to translate that to the Seachkick DSL. It this possible and supported?
I'm running Searchkick 4.4 and Elasticsearch 7.
Because Elasticsearch stores IDs as strings rather than integers, I solved this problem by adding a new obj_id field in ES and ordering results based on that.
In my Post and Project models:
def search_data
{
:obj_id => id,
:title => title,
:content => ActionController::Base.helpers.strip_tags(content),
}
end
And in the controller I changed the order value to:
:order => { :obj_id => :desc }
The records are sorting correctly now.

Rails: Most efficient way to check if a new record already exists in DB

Lets say I have a model Product.
Once in a while I get a file containing new products, the issue is that some of them may already have been entered into the DB.
The data doesn't contain any unique key and the can come structured differently with different fields. What I can do is select from the DB according to all the data I have and if a product is found, not to save the one from the file.
Product.where(:name => p.name, :desc => p.desc, :source => "some source", [more fields])
So my question is if there is a better rails way to check if the record already exists?
Inserting to fail on some unique key, isn't such a good idea IMO but can work too.
You can use the exist? function like this :
if Product.where(:name => p.name, :desc => p.desc, :source => "some source", [more fields])
# do something
else
# do something else
end
You can also use the find_or_create_by if your goal is to create a new record if it does not exist like this :
Product.find_or_create_by(:name => p.name, :desc => p.desc, :source => "some source", [more fields])

How to get the latest record from each group in ActiveRecord?

In my Ruby on Rails application I have a database structure like this:
Project.create(:group => "1", :date => "2014-01-01")
Project.create(:group => "1", :date => "2014-01-02")
Project.create(:group => "1", :date => "2014-01-03")
Project.create(:group => "2", :date => "2014-01-01")
Project.create(:group => "2", :date => "2014-01-02")
Project.create(:group => "2", :date => "2014-01-03")
# and so forth...
How can I get the latest record from each group using ActiveRecord?
The solution is probably simple but I can't get my head around this.
Thanks for any help.
Postgres
In Postgres, this can be achieved with the following query.
SELECT DISTINCT ON ("group") * FROM projects
ORDER BY "group", date DESC, id DESC
Because the date column might not be unique here, I have added an additional ORDER BY clause on id DESC to break ties in favor of the record with the higher ID, in case two records in a group have the same date. You might instead want to use another column like the date/time of the last update or so, that depends on your use case.
Moving on, ActiveRecord unfortunately has no API for DISTINCT ON, but we can still use plain SQL with select:
Project.select('DISTINCT ON ("group") *').order(:group, date: :desc, id: :desc)
or if you prefer using ARel instead of having raw SQL:
p = Project.arel_table
Project.find_by_sql(
p.project(p[Arel.star])
.distinct_on(p[:group])
.order(p[:group], p[:date].desc, p[:id].desc)
)
MySQL
For other databases like MySQL this is unfortunately not as convenient. There are a variety of solutions available, see for example this answer.
I spent some time battling this and thought I'd share what I found to be the cleanest and stunningly easy solution (assuming date or other sorting field contains unique values):
Project.group(:group).maximum(:date)
Hat tip to qarol for posting this in this comment.
This works for me
ids = Message.select("MAX(id) AS id").group(:column_name).collect(&:id)
#result = Message.order("created_at DESC").where(:id => ids)
Following solution based on this link works for MySQL and it's extensible to all fields in group table.
Project.select(:group, 'MAX(date) AS date').group(:group)
Something like this?
Project.select(:group).map(&:group).uniq.each do |grp|
puts Project.where(group: grp).order("date DESC").last
end
This will go through all your groups and identify the unique ones. In your example it should return ["1", "2"]. Then it iterates over that array and selects the last Project with a group id of 1 and the last Project with a group id of 2.
** Update **
Just realized you said "latest" and not "last" which required adding an order to ensure latest works. Last still pulls just one.
Project.where(:group => "1", :date => "2014-01-01").last
.last is what you are looking for.

how to conect a postgresql database to combobox on ruby form

My question is this, I have my postgres database called gas_stations and only has a field called name, and I need that the form shows all the data in combobox from the table. also one of the options should appear "new station" and the truth I don't know how to do this
I think you tale about table and not database. To do this, you must to create a model called GasStation like this :
class GasStation < ActiveRecord::Base
end
After that, you could create a list in your view like this :
select("gas_station", "name", GasStation.all.collect {|gs| [ gs.name, gs.id ] }, { :include_blank => true })
See the guide here : http://guides.rubyonrails.org/getting_started.html.
select("form_name", "gas_station_id", GasStation.all.collect {|g| [ g.name, g.id ] }, { :include_blank => true })
Something like this should get you started. Of course you need to create the Model etc ...
If you don't know how, use a quick tutorial to learn rails basics!

How to search for a text with Active Record in Ruby on Rails 3?

How do I search for a string in Ruby on Rails?
For example, all records with columns that contains "text".
Does Active Record have a method for it or do I have to use SQL "LIKE" for it?
Model.find(:all, :conditions => ['name LIKE ?', "%#{tag}%"])
Where tag is your variable containing the string
as per #bjg comment:-
Or in Rails 3 you'd write this as
Model.where(["name LIKE :tag", {:tag => tag}])
using the new finder syntax –
Sql like may be very inefficient in some cases, for example in many cases in MySQL. I recommend using some full-text indexing software like Sphinx, Xapian or Lucene.
you can also use Arel's 'match' method:
Model.match(:name => tag)
if you want to search in all columns, then you should write some extra code.
If you are deploying to heroku or don't mind dropping db agnosticism, postgres has full text search support. You won't need to run an additional service. Besides PG is the best OS database.
http://tenderlove.github.com/texticle/
I think acts_as_ferret plugin would be perfect for your needs, this plugin allow you to configure easily very cool indexes like
ActsAsFerret::define_index( 'my_index',
:models => {
SomeModel => {
:fields => {
:name => { :boost => 4, :store => :yes, :via => :ferret_title },
:foo => { :store => :no, :index => :untokenized },
:baz => { :store => :yes, :via => :ferret_content }
}
}
} )
All acts_as_ferret indexes are configured in a single file, RAILS_ROOT/config/aaf.rb
find this tutorial it looks nice
full text search in ruby on rails 3
(ferret)
Github source: http://github.com/jkraemer/acts_as_ferret/tree/rails3
The original plugin: http://ferret.davebalmain.com/trac/wiki/FerretOnRails

Resources