cycle() an image_tag - ruby-on-rails

I'm want to display different image version:
first article: big banner
second: small banner that float to right/left
so, first thing: use cycle() but dont work:
= cycle(image_tag(banner_big), image_tag(banner_small)
or
= image_tag(cycle(banner_big_path, banner_small_path))
Only first image is displayed
There's a proper way to make one like that ?

Your problem is that rails is expecting you to call cycle with the same set of strings each time. At the moment you're passing a different pair of strings to each call to cycle, so rails resets the cycle each time. New cycles always start with their first value, hence the result you describe.
Assuming your articles had methods called small_path, big_path, something like
article.send(cycle("big_path","small_path"))
Should return alternate image paths.

You can make use of the session facility to store indexes there and use those. For instance:
# application_helper.rb
def session_banner_index
session[:banner_index] || 0
end
def session_banner(*list)
list[session_banner_index % list.length]
end
# application_controller.rb
def increment_session_banner_index!
session[:banner_index] = (session[:banner_index] || 0) + 1
end
These helper methods approximate the interface you were asking for:
= image_tag(session_banner(banner_big, banner_small))

Related

Why I cannot access to this instance variable (in model) from another method?

I have a method in my model and I call it with before_create:
def first_position
if [...]
[...]
else
#last_known = Picture.where(user_id: user_id).order('position desc').first
self.position = nil
end
end
And I have another method that I call with after_commit:
def default_position
pictures = Picture.where(user_id: user_id).where('created_at > ?', #last_known.created_at)
i = #last_known.position + 1
pictures.each do |pic|
pic.position = i
i += 1
end
end
But in default_position, #last_known returns nil. Do you know why?
EDIT:
Well, I discovered that I have two commit, but the one that concerns the picture is second, so #last_known is set at the first commit but disappears at the second commit.
Initially I thought that ActiveRecord reloads the record sometime before the after_commit, or at least reinitializes it. I've checked with Rails 5.2.1 and nothing happens with instance variables, they remain correctly set. This means that (unless you're using older Rails), there simply are no pictures for the given user and your code does not seem to handle that.
Also, your after_commit will run after you update the object as well, which might be the issue as your variable will not be set in that case.

Best practice for a big array manipulation with values that never change and will be used in more than one view

What would be the best and more efficient way in Rails if I want to use a hash of about 300-500 integers (but it will never be modified) and use it in more than one view in the application?
Should I save the data in the database?, create the hash in each action that is used? (this is what I do now, but the code looks ugly and inefficient), or is there another option?
Why don't you put it in a constant? You said it will never change, so it fits either configuration or constant.
Using the cache has the downside that it can be dropped out of cache, triggering a reload, which seems quite useless in this case.
The overhead of having it always in memory is none, 500 integers are 4KB or something like that at most, you are safe.
You can write the hash manually or load a YAML file (or whatever) if you prefer, your choice.
My suggestion is create a file app/models/whatever.rb and:
module Whatever
MY_HASH = {
1 => 241
}.freeze
end
This will be preloaded by rails on startup (in production) and kept in memory all the time.
You can access those valus in view with Whatever::MY_HASH[1], or you can write a wrapper method like
module Whatever
MY_HASH = {
1 => 241
}.freeze
def self.get(id)
MY_HASH.fetch(id)
end
end
And use that Whatever.get(1)
If the data will never be changed, why not just calculate the values before hand and write them directly into the view?
Another option would be to put the values into a singleton and cache them there.
require 'singleton'
class MyHashValues
include Singleton
def initialize
#
#results = calculation
end
def result_key_1
#results[:result_key_1]
end
def calculation
Hash.new
end
end
MyHashValues.instance.result_key_1
Cache it, it'll do exactly what you want and it's a standard Rails component. If you're not caching yet, check out the Rails docs on caching. If you use the memory store, your data will essentially be in RAM.
You will then be able to do this sort of thing
# The block contains the value to cache, if there's a miss
# Setting the value is done initially and after the cache
# expires or is cleared.
# put this in application controller and make it a helper method
def integer_hash
cache.fetch('integer_hash') { ... }
end
helper_method :integer_hash

Ruby on Rails method returning nothing

I'm new to ruby and just testing out how to define a method with two variable inputs from the user. Currently, it takes the values but it returns nothing.
Is there something I missing here?
puts "Tell me what you want to print."
word = gets.chomp
puts "How many times do you want it printed?"
number = gets.to_i
def print_x_times(word)
i = 0
while i < number
puts(word)
i += 1
end
end
A few nits here:
You've defined a new method, but you haven't invoked it. You're likely using something like IRB to interactively play around, but the fact remains that you've only defined that method.
You're going to confuse yourself if you use word and number as variables inside of that method, since they're not guaranteed to be the same as the ones you've defined outside of it.
If you want to pass two values to the method, then you have to specify two parameters:
def print_x_times(word, number)
# code
end
...then, you actually go about calling it with your variables.
print_x_times(word, number)
You should pass number as an argument to the function print_x_times as you do for word
moreover, this code defines a function but doesn't call it, you should call it too
You have two issues here...
You need to define the method to take two parameters, word and number.
Then you need to call that method with the two arguments you derived from user input.

How to create hash with automatically generated ranges in rails

I want to create a simple timer, that start from 0, has_many points and stop working when i push stop button.
Timer.start == 0
Timer.point = Time.now
Timer.fin = Time.now
I would like to create a timeline hash with ranges for every points in seconds.
Something looks like Timeline.new(timer.point.first[0..4], timer.point.second[5..11] ... timer.point.last [42..56])
I think I should use an iteration, but have no idea how setup point[from..till] arguments. Sorry, don't have much practice.
Any solutions, ideas?
TY4HLP
You can try to use while loop for your task

Allow an action once per session

I have a site that tracks video views... every time the controller is called. One could flood their own video views with some heavy F5ing.
How to make it so a view counts or a method runs only once per session?
def show
new_views = #video.views + 1
#video.update_attributes(:views => new_views)
end
You can create a session variable, probably upon login, like :
session[:is_logged] = 1
Then, every time you are about to increment the counter, just check this variable.
Single session variable doesn't work because you have many videos and you would like to separate counts for different videos. I think that a better way is to store view events in db.
pros: you can even allow action once
per user avoiding login/logout
cons: huge size of users_videos table
Well the simplest way would be to track it in the session itself:
def show
if session[:has_counted_view] == nil
new_views = #video.views + 1
#video.update_attributes(:views => new_views)
session[:has_counted_view] = true
end
end

Resources