Rails query and order with same array used for query - ruby-on-rails

I have method
def self.get_ayahs_by_array(ayahs_keys_array)
self.where(ayah_key: ayahs_keys_array)
end
Which does a query on the Quran::Ayah model. ayahs_keys_array is an array of keys (primary_key) in a certain order. The query returns a different order, but I want it to return as the same order as the queried array.
Example: ayahs_keys_array is [5,4,1,2,7] and I want it to return in THAT order and not [1,2,4,5,7]
Any ideas?

In MySql:
self.where(ayah_key: ayahs_keys_array).order("FIELD(ayah_key, #{ ayahs_keys_array.joins(', ') })")
For postgres is slightly more complicated as you need to build whole CASE statement. Might be easier to do it on the application level:
self.where(ayah_key: ayahs_keys_array).order_by {|r| ayahs_keys_array.index r.ayah_key}
Finally, you can try this gem: https://github.com/panorama-ed/order_as_specified. If you do, please let us know how it went as I never used it.

Related

How to add attribute/property to each record/object in an array? Rails

I'm not sure if this is just a lacking of the Rails language, or if I am searching all the wrong things here on Stack Overflow, but I cannot find out how to add an attribute to each record in an array.
Here is an example of what I'm trying to do:
#news_stories.each do |individual_news_story|
#user_for_record = User.where(:id => individual_news_story[:user_id]).pluck('name', 'profile_image_url');
individual_news_story.attributes(:author_name) = #user_for_record[0][0]
individual_news_story.attributes(:author_avatar) = #user_for_record[0][1]
end
Any ideas?
If the NewsStory model (or whatever its name is) has a belongs_to relationship to User, then you don't have to do any of this. You can access the attributes of the associated User directly:
#news_stories.each do |news_story|
news_story.user.name # gives you the name of the associated user
news_story.user.profile_image_url # same for the avatar
end
To avoid an N+1 query, you can preload the associated user record for every news story at once by using includes in the NewsStory query:
NewsStory.includes(:user)... # rest of the query
If you do this, you won't need the #user_for_record query — Rails will do the heavy lifting for you, and you could even see a performance improvement, thanks to not issuing a separate pluck query for every single news story in the collection.
If you need to have those extra attributes there regardless:
You can select them as extra attributes in your NewsStory query:
NewsStory.
includes(:user).
joins(:user).
select([
NewsStory.arel_table[Arel.star],
User.arel_table[:name].as("author_name"),
User.arel_table[:profile_image_url].as("author_avatar"),
]).
where(...) # rest of the query
It looks like you're trying to cache the name and avatar of the user on the NewsStory model, in which case, what you want is this:
#news_stories.each do |individual_news_story|
user_for_record = User.find(individual_news_story.user_id)
individual_news_story.author_name = user_for_record.name
individual_news_story.author_avatar = user_for_record.profile_image_url
end
A couple of notes.
I've used find instead of where. find returns a single record identified by it's primary key (id); where returns an array of records. There are definitely more efficient ways to do this -- eager-loading, for one -- but since you're just starting out, I think it's more important to learn the basics before you dig into the advanced stuff to make things more performant.
I've gotten rid of the pluck call, because here again, you're just learning and pluck is a performance optimization useful when you're working with large amounts of data, and if that's what you're doing then activerecord has a batch api you should look into.
I've changed #user_for_record to user_for_record. The # denote instance variables in ruby. Instance variables are shared and accessible from any instance method in an instance of a class. In this case, all you need is a local variable.

Access hash by primary key - ruby rails

I thought this could be done trivially but I am unable to do so.
My current code is:
#player_types = squad.player_types
Now I loop and lookup for the id,
params[:player_types].each do |p_type|
#player_types.find(p_type[:id])
end
Why does #player_types.find(p_type[:id]) have to execute the the select query when I look up the server logs, havent I loaded this. Is it because of the lazy evaluation and is there a way to load everything at the start and access it as an index in the hash?
The better way to use arel gem, and to select all record with specific ids is this:
ids = params[:player_types].map {|v| v[:id] }
#player_types.where(#player_types.class.arel_table[:id].in(ids))
If player_types is a table, you can directly select all of the player_types in the params[:player_types] array by passing the array to a where condition.
#player_types = PlayerType.where(id: params[:player_types])

Returning a hash instead of array with ActiveRecord::Base.connection

I have to use a query like this :
query = Enc.joins(:rec).group("enc.bottle").
select("enc.bottle as mode, count(rec.id) as numrec, sum(enc.value) as sumvalue")
That I use with :
#enc = ActiveRecord::Base.connection.select_all(query)
To get the data, I've to do #enc.rows.first[0] (it works)
But #enc.rows.first["mode"] doesn't work ! Because each row of #enc.rows contains array.. not a map with the name of each field.
Maybe select_all is a wrong method.
Does it exist another method to get the data with the name of field ?
Thank you
EDIT
If you can associate a model with the query, then there's no need for the generic select_all method. You can use find_by_sql like this:
Enc.find_by_sql(query).first.mode
# => testing
Note that you will no be able to see the aliases when inspecting the results, but they are there. Also, the convention is to use plural names for the tables. You might find it easier to just sticks with the defaults.

How to get table column value?

I write follow code to get one record from the table webeehs:
webeehs_result = Webeeh.find(:all, :conditions=>["webeeh_project_id=#{project_id}"])
Then I want to get one column value from this record, how could I do?
For example, the column name is webeeh_date.
first of all, never EVER write code like that. Building your own conditions as pure strings can leave you vulnerable to SQL injection exploits. If you must do conditions, then do it like this:
:conditions => ["webeeh_project_id = ?", project_id]
if you have a Project model, you should rename the webeeh_project_id column from your Webeeh model into project_id and have an association in your Project model like has_many :webeehs
Then, you won't need to call that find anymore, just do a p = Project.find(id) and then p.webeehs will return the webeehs you need.
the result will be an array which you can iterate through. And to get your webeeh.webeeh_date member, just call it like this:
result.each do |webeeh|
date = webeeh.webeeh_date
end
webeehs_result = Webeeh.findwebeeh_dates
is enough to get all columnn values.
For a different method and performance issues check the following: http://www.stopdropandrew.com/2010/01/28/finding-ids-fast-with-active-record.html
webeeh_result will usually be an array of results for the database.
You can iterate throughit using
webeehs_result.each do |webeeh|
# use "webeeh.webeeh_date" to access the column_name or do whatever you want with it.
end

Random jokes in a skit (activerecord)

I am working on populating my database with test data using populate.rake:
Repertoire.includes(:jokes).each do |r|
#jokes = r.jokes
Skit.populate 8..12 do |skit|
skit.joke_id = #jokes[rand(#jokes.count)].id
end
end
This is giving me a RuntimeError: Called id for nil.
How can I populate a skit with random jokes?
sort_by {rand} should sort your array of jokes.
Or, there is also doing an .order("rand()/random()") (depending on your db) in your Repertoire query and putting a limit on the query.
Not sure if this will fix your problem but Ruby has a rand method for arrays so you should be able to call #jokes.rand.id instead. Seems like that would simplify things and maybe even fix your error.

Resources