ActiveRecord query alias field name output in jBuilder - ruby-on-rails

Hi I am new to ruby on rails development. This is my controller function query
def index
#questions = Question.order('questions.created_at DESC').joins('left join favourites on questions.id=favourites.question_id and favourites.user_id='+current_user_id.to_s).includes(:user).select('CASE WHEN favourites.user_id='+current_user_id.to_s+' THEN 1 ELSE 0 END as favour').references(:favourite).page(params[:page]).per( (ENV['ILM_QUESTIONS_PER_PAGE'] || 15).to_i )
end
From this query i dont know how to get the value for "favour" column in select query.
This is my jbuilder file in views
/index.json.builder
json.number_of_items_per_page #questions.length
json.total_number_of_pages #questions.total_pages
json.user_favour #questions.favour
json.questions do
json.array! #questions do |question|
json.partial! 'api/v1/questions/question', question: question,include_comments: false
end
end
/_question.json.builder
json.id question.id
json.content question.content
json.created_at question.created_at
json.image_url question.image.url
when i put #questions.favour in index.json.builder
i got this error
undefined method `favour' for #<Question::ActiveRecord_Relation:0x0000000c39b5f0>
Please Advice me on this issue
Thanks in Advance.

Related

Find a best way to work with redis cache on rails

I try to use Redis to cache on rails, but I get a challenge when trying to cache multi-language. Because my Redis needs to be cached with table_translations
I try with some code, but I don't think this is the best way
I have the instance variable to work with Erb template
def index
#posts = fetch_posts
#translations = fetch_translations
puts #posts
puts #translations
end
and Redis fetch like this
private
def fetch_posts
begin
posts = $redis.get "posts"
if posts.nil?
posts = []
Post.all.order("id ASC").each do |post|
posts << post
end
posts = posts.to_json
$redis.set "posts", posts
end
posts = JSON.load posts
rescue => error
puts error.inspect
posts = Post.all
end
posts
end
def fetch_translations
begin
translations = $redis.get "translations"
if translations.nil?
translations = []
Post.all.order("id ASC").each do |post|
post.translations.order("locale ASC").each do |translation|
translations << translation
end
end
translations = translations.to_json
$redis.set "translations", translations
end
translations = JSON.load translations
rescue => error
puts error.inspect
translations = Post.all
end
translations
end
I do that because I need to get all language version of a post, so I make a Redis key for translate
and my output:
{"id":1,"slug":"hello-world","thumb_url":"thumbs/null","thumb_file_name":null,"thumb_content_type":null,"thumb_file_size":null,"thumb_updated_at":null,"featured":false,"hidden":false,"created_at":"2019-04-18T07:05:09.117Z","updated_at":"2019-04-18T07:27:55.830Z"}
{"title":"Xin chao","description":"Day la bai viet dau tien, duoc viet tu rails CMS","body":"xin chao cac ban"}
{"title":"Hello World","description":"This is first post from rails CMS","body":"Hello every body"}
I find the best solution to make my output into a key, like this:
{"id":1,"slug":"hello-world","thumb_url":"thumbs/null","thumb_file_name":null,"thumb_content_type":null,"thumb_file_size":null,"thumb_updated_at":null,"featured":false,"hidden":false,"created_at":"2019-04-18T07:05:09.117Z","updated_at":"2019-04-18T07:27:55.830Z","title":"Xin chao","description":"Đay la bai viet đau tien, đuoc viet tu rails CMS","body":"xin chao cac ban"}
{"id":1,"slug":"hello-world","thumb_url":"thumbs/null","thumb_file_name":null,"thumb_content_type":null,"thumb_file_size":null,"thumb_updated_at":null,"featured":false,"hidden":false,"created_at":"2019-04-18T07:05:09.117Z","updated_at":"2019-04-18T07:27:55.830Z",title":"Hello World","description":"This is first post from rails CMS","body":"Hello every body"}
My code can work correctly, but I need your help to make it better, please help me to improve my skills
Thank for your help
You can use the built in Rails cache handler, this way you won't need to handle .nil? calls to cache keys.
private
def fetch_posts
posts = Rails.cache.fetch("posts") do
begin
Post.all.order("id ASC").as_json
rescue => error
puts error.inspect
Post.all
end
end
posts
end
def fetch_translations
translations = Rails.cache.fetch("translations") do
begin
Post.all.order("id ASC").map do |post|
post.translations.order("locale ASC").as_json
end.flatten
rescue => error
puts error.inspect
Post.all
end
end
translations
end
I found the solution by follow this stuff How do you add an array to another array in Ruby and not end up with a multi-dimensional result?
concept is flatten all attr in two array and then Hash again this into new array
def fetch_posts
posts = []
Post.all.order("id ASC").each do |post|
post.translations.each do |translation|
posts << [*post.attributes.slice('slug','thumb_url'),*JSON.parse(translation.to_json)].to_h
end
end
end
Hope this help to anyone have question same to me :)

Parsing array of multiple objects in Jbuilder

How to extract values present in array of multiple object's using jbuilder.?
i have an array of multiple objects.
#array1= [ ]
#pushed different types of objects into this array.
if xyz
#array1 << object_type1 # having fields id,f_name
else
#array1 << object_type2 # having fields id,l_name
Now in jbuilder i want
json.array! #array1 do |myarray|
json.id myarray.id
json.name myarray.f_name || myarray.l_name # how to check object type here
end
when i try this it is giving me error like
undefined method `l_name' for #<Object_type1:0xb496eda8>
How to check or tell jbuilder to which objecttype it has to use for name field.?
If both of your ObjectTypes are ActiveRecord models, you can do something a bit cleaner like:
json.array! #array1 do |myarray|
json.name myarray.has_attribute? "f_name" ? myarray.f_name : myarray.l_name
json.id myarray.id
end
This checks if myarray has an attribute of f_name and if it does uses that, otherwise we know it's the other ObjectType so we use l_name. If you haven't seen a one line if/else statement like this before, the syntax I'm using is:
<condition> ? <if_true> : <if_false>
So you can do things like:
#post.nil? ? return "No post here" : return "Found a post"
Or you can add a method to each of your ObjectTypes in their models like:
def name
l_name # or f_name, depending on which ObjectType it is
end
Then you could do:
json.array! #array1 do |myarray|
json.name myarray.name
json.id myarray.id
end
i don't know whether it is a correct way or not but i tried and got what i wanted
json.array! #array1 do |myaarray|
if myarray.class == ObjectType
json.name myarray.f_name
json.id myarray.id
else
json.name myarray.l_name
json.id myarray.id
end
end

kaminari undefined method 'page'

I am trying to add Kaminari to my Rails app. I have included the gem and this is what my controller looks like:
def index
if params[:year]
if params[:year].size > 0
#songs = Song.where("year like ?", params[:year]).page(params[:page])
elsif params[:artist].size > 0
#songs = Song.where("artist_name like ?", params[:artist]).page(params[:page])
elsif params[:song].size > 0
#songs = Song.where("title like ?", params[:song]).page(params[:page])
end
else
#songs = Song.first(10).page(params[:page])
end
end
and then adding
<%= paginate #songs %>
in my view, the error I am getting is:
undefined method `page' for #<Array:0x007fab0455b4a8>
Not sure why this is coming up as I followed the docs step for step.
Kaminari uses paginate_array to paginate an array. 2 solutions:
First, you can use limit(10) instead of first(10):
#songs = Song.limit(10).page(params[:page])
Second, use paginate_array
#songs = Kaminari.paginate_array(Song.first(10)).page(params[:page])
I'd advise you rewrite your controller slightly. Better yet, move your filters to the model or a filter class. Look into present? for testing existence of params as that will check for nil and empty.
def index
#songs = Song
#songs = #songs.where("year like ?", params[:year]) if params[:year]
#songs = #songs.where("artist_name like ?", params[:artist]) if params[:artist]
#songs = #songs.where("title like ?", params[:song]) if params[:song]
#songs = #songs.limit(10).page(params[:page])
end
Tl;DR If you use Mongoid, use kaminari-mongoid instead of kaminari alone.
At Github it said, Kaminari supports Mongoid...so I went and installed gem 'kaminari' with the result: unknown method :page...later i found the mongoid adapter: kaminari-mongoid and that works now.

IF conditions in rails is not executing

I'm trying to do solr search based on the text entered by the user. Firts I've to check whether the entered text is store or brand or category. After checking that condition I want to display corresponding riesults which are in the MainNavigationUrls table using solr search. Here is the controller action. It is working fine if I enter any store and can get proper results. But it is not going inside brands loop if the storesearch is found nill. Please explain why it is not executing the second case.
def search_all
#storesearch=Site.search do
fulltext params[:text]
with(:multibrand,1)
end
if(#storesearch.nil?)
#brandsearch=Brand.search do
fulltext params[:text]
end
if(#brandssearch.nil?)
#itemcategorysearch=MainCategory.search do
fulltext params[:text]
end
#itemcategorysearch.results.each do |result|
#itemcategorysearch1=MainNavigationUrl.search do
with :main_categoty_id, result.id
with :department_id, params[:deptid].to_i
paginate :page=>params[:page], :per_page=>45
end
end
else
#brandsearch.results.each do |result|
#brandsearch1=MainNavigationUrl.search do
with :brand_id, result.id
with :department_id, params[:deptid].to_i
paginate :page=>params[:page], :per_page=>45
end
end
else
#storesearch.results.each do |result|
#storesearch1=MainNavigationUrl.search do
with :site_id, result.id
with :department_id, params[:deptid].to_i
paginate :page=>params[:page], :per_page=>45
end
end
end
end
instead of .nil? ,maybe you can use .blank? is better?
#array = []
#array.nil? -false
#array.blank? -true
I think you are checking if #storesearch contain some elements?

Get an array of associations from an array of objects?

I have an array of Pictures. Each picture has_many comments.
If I have an array of pictures #pictures, how can I get all comments with a certain attribute from all pictures in #pictures? Is there a nice Ruby one-liner for the following code?:
#comments = []
#pictures.each do |pic|
pic.comments.each do |comment|
if comment.text == "test"
#comments << comment
end
end
end
Note: I know I can probably get this in one line from a database query, but I figure it would be more efficient to use the data that I already have, rather than re-query the database for ALL pictures, when I only care about a certain subset of pictures that I already have.
#comments =
#pictures
.flat_map(&:comments)
.select{|comment| comment.text == "test"}
map + select should do the trick:
#comments = #pictures.map(&:comments).flatten.select{|c| c.text == "test"}

Resources