Find a best way to work with redis cache on rails - ruby-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 :)

Related

Prawn: How to iterate from a table inside an iteration in the header?

I pass 3 #course ID's to courses.pdf.
Then Prawn generates a PDF of 3 pages - one course pr page.
The problem: currently it prints all #participants from all 3 courses in all 3 pages.
It should only print the #participants for the current course in a table.
I have spend several hours trying different methods, asked in Facebook groups and searched Stackoverflow + Google for solutions.
class CoursesToPrintPdf < Prawn::Document
def initialize(courses, participations)
#courses = courses
#participations = participations
header
end
def header
#courses.order('day ASC').each do |course|
text_box("#{course.course_day_pdf}",
:align => :right)
text "#{course.round.round_name_simple}"
table deltakere_rows do
self.header = true
end
end
end
def deltakere_rows
[["ID", "Name"]] +
#participations.map do |p|
[p.participant.id, p.participant.full_name]
end
end
end
Does a partecipation contain a course reference? If so, it could be something like this
def deltakere_rows(course)
[["ID", "Name"]] +
#participations.select do |p|
p.course_id == course.id
end.map do |p|
[p.participant.id, p.participant.full_name]
end
end
And pass the course to deltakere_rows
table deltakere_rows(course) do
self.header = true
end
This could be the idea with the info we have

ActiveRecord query alias field name output in jBuilder

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.

How to create an array of methods in rails

def id_attachment_require_upload?
!object.id_attachment?
end
...
def work_attachment_require_upload?
!object.work_attachment?
end
I want to make it like below.
array = %w(id address work)
array.each do |a|
def #{a}_attachment_require_upload?
!object.#{a}_attachment?
end
end
Is there any way for me to create a array of methods automatically in rails to save me from the redundant work.
array = %w(id address work)
array.each do |a|
define_method "#{a}_attachment_require_upload?" do
!object.public_send("#{a}_attachment?")
end
end
Arup's answer looks like it's the way to go but I'm not sure if object.#{a}_attachment? will work. If it does, then I learned something new today. You can also use public_send.
array = %w[id address work]
array.each do |a|
define_method "#{a}_attachment_require_upload?" do
!object.public_send("#{a}_attachment?")
end
end

In Rails how do I use find_each method with index?

I can use Rails find_each method like :
User.find_each(:batch_size => 10000) do |user|
------
end
With find_each method is there any way to get the index of the array ? like :
User.find_each(:batch_size => 10000).with_index do |user, index|
------
end
As an update to this question. Active Record 4.1.4 has added support for find_each.with_index as pointed in the documentation.
User.find_each(:batch_size => 1000).with_index do |user, index|
user.call_method(index)
end
Update: As of Rails 4.1.4 this is possible. See this answer for more. Example:
User.find_each(:batch_size => 1000).with_index do |user, index|
user.call_method(index)
end
As you can see from the method definition, this is not possible.
def find_each(options = {})
find_in_batches(options) do |records|
records.each { |record| yield record }
end
end
In order to accomplish what you want to do, you need to either create your own modified version of the method
class User
def find_each(options = {})
find_in_batches(options) do |records|
records.each_with_index { |record| yield record, index }
end
end
end
User.find_each(:batch_size => 10000) do |user, index|
------
end
or use an instance variable.
index = 0
User.find_each(:batch_size => 10000) do |user|
# ...
index += 1
end
There is no other default solution as shown by the method implementation.
Your question is already implemented in the Rails master branch. To get this, it requires using Rails edge, as this has not been merged into any release as of yet. See this merged pull request: https://github.com/rails/rails/pull/10992.
So add this to your Gemfile:
gem 'rails', github: 'rails/rails'
This will allow you to run the code you described:
User.find_each(batch_size: 10000).with_index do |user, index|
puts "UserID: #{user.id.to_s} has index ##{index.to_s}"
end
Granted, running on the edge release is risky, so don't do this in production. But look at the pull request to see the small amount of code added to get this working. You can monkey patch until it is merged into a Rails release.
Just use an local variable:
index = 0
User.find_each(:batch_size => 10000) do |user|
------
index += 1
end
You can get all users and send them through a block along with their corresponding index as follows.
User.all.each_with_index do |user, index|
puts "email is " + "#{user.email}" + " and user index is " + "#{index}"
end

Rails 3: Search method returns all models instead of specified

What I'm trying to do: I have a model "Recipe" in which I defined a method "search" that takes an array of strings from checkboxes (I call them tags), and a single string. The idea is to search the db for recipes that has anything in it's 'name' or 'instructions' that contains the string, AND also has any of the tags matching it's 'tags' property.
Problem: The search method return all the recipes in my db, and doesn't seem to work at all at finding by the specific parameters.
The action method in the controller:
def index
#recipes = Recipe.search(params[:search], params[:tag])
if !#recipes
#recipes = Recipe.all
end
respond_to do |format|
format.html
format.json { render json: #recipe }
end
end
The search method in my model:
def self.search(search, tags)
conditions = ""
search.present? do
# Condition 1: recipe.name OR instruction same as search?
conditions = "name LIKE ? OR instructions LIKE ?, '%#{search[0].strip}%', '%#{search[0].strip}%'"
# Condition 2: if tags included, any matching?
if !tags.empty?
tags.each do |tag|
conditions += "'AND tags LIKE ?', '%#{tag}%'"
end
end
end
# Hämtar och returnerar alla recipes där codition 1 och/eller 2 stämmer.
Recipe.find(:all, :conditions => [conditions]) unless conditions.length < 1
end
Any ideas why it return all records?
if you are using rails 3, then it is easy to chain find conditions
def self.search(string, tags)
klass = scoped
if string.present?
klass = klass.where('name LIKE ? OR instructions LIKE ?', "%#{string}%", "%#{string}%")
end
if tags.present?
tags.each do |tag|
klass = klass.where('tags LIKE ?', "%#{tag}%")
end
end
klass
end
When you do
search.present? do
...
end
The contents of that block are ignored - it's perfectly legal to pass a block to a function that doesn't expect one, however the block won't get called unless the functions decides to. As a result, none of your condition building code is executed. You probably meant
if search.present?
...
end
As jvnill points out, it is in general much nicer (and safer) to manipulate scopes than to build up SQL fragments by hand

Resources