I have a rails application, with a model that is a kind of repository.
The records stored in the DB for that model are (almost) never changed, but are read all the time. Also there is not a lot of them.
I would like to store these records in cache, in a generic way.
I would like to do something like acts_as_cached, but here are the issue I have:
I can not find a decent documentation for acts as cached (neither can I find it's repository)
I don't want to use memcached, but something simpler (static variable, or something like that).
Do you have any idea of what gems I could use to do that ?
Thanks
EDIT
I am still looking for something similar to cache_flu but without memcached
Could you store the data in a file and load it into a constant (as suggested on Ruby on Rails: Talk):
require "yaml"
class ApplicationController < ActionController::Base
MY_CONFIG = YAML.load(File.read(File.join(RAILS_ROOT, "config", "my_config.yml")))
end
I have started a gem called cache_me which can work with any cache_store
it's in Alpha mode but you can give a try and then open some pull request / Issues.
https://github.com/arunagw/cache_me
I will let you know when it's ready to use full mode.
acts_as_cached was superseded by cache_fu.
You can store data in rails default cache or, as seems to be the most popular choice, use mem_cache_store which uses memcached.
#production.rb
config.cache_store = :mem_cache_store, '127.0.0.1:11211', {:namespace => "production"}
#some_helper.rb
def get_some_data
Rails.cache.fetch('some_reference'){Model.find_some_data}
end
See also:
http://guides.rubyonrails.org/caching_with_rails.html
Also, if you're using passenger you'll need to do this:
if defined?(PhusionPassenger)
PhusionPassenger.on_event(:starting_worker_process) do |forked|
if forked
Rails.cache.instance_variable_get(:#data).reset if Rails.cache.class == ActiveSupport::Cache::MemCacheStore
else
# No need to do anything.
end
end
end
Related
This issue relates to a need to set a Rails config variable as the application boots, and the value of that variable needs to come from data in the database (which are then modified). So, I have an initializer with something like this:
require "#{Rails.root}/lib/modules/facet_altering.rb"
include FacetAltering
Rails.application.config.reject_subjects = FacetAltering.reject
The reject method is potentially slow and calls the Subject model (which includes some concerns).
If I try to require subject.rb, application_rb and the relevant concerns from app/models then I progress a bit further, but eventually get stuck on uninitialized constant Subject::MySpecialConcern.
There might be some better way to set the reject_subjects value; I'd prefer not to run FacetAltering.reject each time the value of reject_subjects is used, though this might be an easy 'fix' if no other solution arises (at the cost of slowing things down). Or, is there another way to access these classes as the application boots?
Edit: Following on from the comment below, this is in config/application.rb:
%W[#{Rails.root}/lib/modules #{Rails.root}/test/mailers/previews].each do |path|
config.eager_load_paths << path
end
This post offered a useful clue:
Rails Model no longer available in initializer after upgrade to Rails 7.0
So, putting my code in config/application.rb as follows did the trick:
config.after_initialize do
Rails.application.config.reject_subjects = FacetAltering.reject
end
Now to find the answer to RuntimeError: Foreign key violations found in your fixture data. Ensure you aren't referring to labels that don't exist on associations. and I might be able to complete this Rails 6 -> 7 upgrade!
I have a basic application running with ruby on rails. I use sqlite3 for development and postgres for production. I recently got access to Orchestrate.io and their student tier.
I would like to know how I could possibly use this with my application. I'm not even sure this is possible. My app is really simple (add-edit-delete). But it would be interesting to have a go at using the tools.
Mostly because I cannot find an efficient and free rails db text search.
You can definitely use Orchestrate as the backend for a Rails application.
A few different options:
The Orchestrate-Ruby client has both a method client & object client. Although the object client is still considered a work-in-progress, the method client provides a solid interface for connecting to the Orchestrate API.
Use an http library (such as rest-client or faraday) to make calls to the Orchestrate API.
There's also the Orchestrate-Rails gem. Your mileage may vary with this (last updated in April).
To use Orchestrate as the only backend (no postgres/mysql), I've found the best approach is to disable ActiveRecord:
When creating a new application, you can use -O to skip ActiveRecord:
rails new my_app -O
For existing applications:
1. Remove database adapter gems from your Gemfile (pg, mysql2, sqlite3, etc.)
2. Change your config/application.rb
Remove require 'rails/all line and require frameworks you want to use, for example:
require "action_controller/railtie"
require "action_mailer/railtie"
require "sprockets/railtie"
require "rails/test_unit/railtie"
3. Delete your database.yml file, db/schema.rb and migrations (if any)
4. Delete migration check in test/test_helper.rb
5. Delete any ActiveRecord configuration from your config/environments files (this is what is causing your error)
If you run into problems/errors, stack trace should give you sufficient information on what you need to change. You might for example have some ActiveRecord configuration in your initializers.
With the Orchestrate-Ruby client, you can define a model like so:
class Foo < Orchestrate::Collection
...
end
I'm still undecided on what the best approach for defining the Application object is, but one way I've done it is by making a global object with an initializer:
# /config/initializers/orchestrate.rb
$App = Orchestrate::Application.new(ENV['ORCHESTRATE_KEY']) # using dotenv gem
$App = Orchestrate::Application.new('your_key_here') # without dotenv
From here, you can then access the $App object in your controllers (to initialize the collection object):
class FoosController < ApplicationController
def index
#foos = Foo.new($App, "foos").each
end
end
Leveraging model concerns might be a better way to share the Application object/API key between models. Or you could roll your own classes on top of the method client.
Hope this helps!
I'll be looking into how to accomplish this in a more 'Railsy' way.
EDIT: also, textacular is a ruby gem which provides full-text search and indexing for postgres
I wanted to use this api: https://github.com/coinbase/coinbase-ruby and the first step is to initialize the API, like this:
coinbase = Coinbase::Client.new(ENV['COINBASE_API_KEY'], ENV['COINBASE_API_SECRET'])
I was wondering what the best place to put this code is, and how would I access it if I put it "there"? I want this variable (coinbase) to be accessible ANYWHERE in the application.
Thanks!
The answer to this question really depends on your use case and your approach. My geral recommendation, however, is to create a Service Object (in the DDD sense) (see the section named "Domain Objects Should Not Know Anything About Infrastructure Underneath" in that link), that handles all communication with the Coinbase API. And then, within this service object, you can simply initialize the Coinbase::Client object once for however many times you call into it. Here's an example:
# app/services/coinbase_service.rb
class CoinbaseService
cattr_reader :coinbase_client, instance_accessor: false do
Coinbase::Client.new(ENV['COINBASE_API_KEY'], ENV['COINBASE_API_SECRET'])
end
def self.do_something
coinbase_client.do_something_in_their_api
end
def self.do_something_else
coinbase_client.do_something_else_in_their_api
end
end
So then you might do, e.g.:
# From MyController#action_1
if CoinbaseService.do_something
# ...
else
# ...
end
Or:
# From MyModel
def do_something
CoinbaseService.do_something_else
end
To get the service object working, you may need to add app/services to your autoload paths in application.rb file. I normally just add this:
# config/application.rb
config.autoload_paths += %W(#{config.root}/app)
I find this Service Object approach to be very beneficial organizationally, more efficient (only 1 invocation of the new Coinbase client needed), easier to test (easy to mock-out calls to Coinbase::Client), and simply joyful :).
One way to go about having a global variable can be done as similar as initializing redis in a Rails application by creating an initializer in config/initializers/coinbase.rb with:
$coinbase = Coinbase::Client.new(ENV['COINBASE_API_KEY'], ENV['COINBASE_API_SECRET'])
Now, you can access $coinbase anywhere in the application!
In the file config/initializers/coinbase.rb
Rails.application.config.after_initialize do
CoinbaseClient = Coinbase::Client.new(
Rails.application.credentials.coinbase[:api_key],
Rails.application.credentials.coinbase[:api_secret])
end
In place of the encrypted credentials, you could also use environment variables: ENV['COINBASE_API_KEY'], ENV['COINBASE_API_SECRET']
The above will make the constant CoinbaseClient available everywhere in your app. It will also ensure all your gems are loaded before the client is initialized.
Note: I am using Rails 6.1.4.4, and Ruby 2.7.5
I am new to Rails and come from a ColdFusion background, where we would store global / site-wide variables in the 'application' scope. This persists the variable across any view or controller. Does Rails 4 have an equivalent functionality for this type of thing?
The site-wide variable won't typically change often so it doesn't need protecting in any way.
For example, in my situation, I want to store the website's domain name. One for testing and one for live environments. Localhost for development and xxxxxx.com for production.
Any tips or pointers would help. I have Googled this extensively and solutions seem to be far too complicated to achieve what seems to be such a trivial task. What's the best elegant solution for Rails 4?
The simplest, basic and default way is to use the Rails.application.config store.
Rails.application.config.my_config = 'foo'
You can assign a config in your environment:
# application.rb
module MyApp
class Application < Rails::Application
config.my_config = 'foo'
end
end
and read it with
Rails.application.config.my_config
# => 'foo'
This approach works well for very simple applications, but if you want something more advanced there are several gems available.
I'm currently using SimpleConfig. The main advantages are:
per-environment configuration. You can configure default configurations for the application, then override defaults with environment specific configurations
local.rb file for custom overrides
capistrano-like configuration style
it works nicely with the dotenv gem, very useful to avoid storing sensitive credentials in your repo.
This sounds like a perfect example for configuration values stored in config/environments/production.rb and config/environments/development.rb. Just store any value there:
config.my_special_value = 'val'
And access it in your application like this:
Rails.application.config.my_special_value
Always the value of your environment is active.
If you just want to have a „global“ value, store it in your application controller. All your view controllers are derived from your app controller, so you can save any value there as an instance or class variable:
class ApplicationController < ActionController::Base
MY_CONSTANT_VALUE = "foo"
end
class MyViewController < ApplicationController
def index
raise MY_CONSTANT_VALUE.inspect
end
end
You also could implement an helper:
# app/helpers/application_helper.rb
module ApplicationHelper
FOO = "bar"
end
# app/controllers/foo_controller.rb
class FooController < ApplicationController
def index
raise FOO
end
end
I can recommend good method to store variable. I use this on production
Passwords can be stored easier to .env file
like this
#Root dir create file ".env"
PASSWORD=123456
and load password
#Somewhere in app
ENV['PASSWORD'] #=> 123456
it works I hope will help you
You can use gem figaro
write your variables in config/application.yml
HELLO: world
development:
HELLO: developers
production:
HELLO: users
Then you can fetch
ENV["HELLO"]
In rails there is gem named as
gem 'dotenv-rails'
By using it we can assign the variables to system level and used in application.
By using simple steps
First create a simple filed in system level at any place with named extension .env
//in application.rb
require 'dotenv'
Dotenv.load('path-of-your-file.env')
And restart your application
Source
Please got the link for the desscription of dot env gem
I have a Rails app that uses a gem called ActsAsTaggableOnSteroids, which is a Rails Engine. Specifically, I'm using PavelNartov's fork of the gem. But nevermind that.
I need to add specific functionality to the Tag model, which is supplied by the engine.
But, according to my understanding of Rails engines and the magical loading functionality in Rails, if I put a file called "tag.rb" in my models directory, then it will completely replace the one from the Engine.
Ideally, I would be able to do something like:
class Tag < ActsAsTaggable::Tag
# my stuff
end
...but alas, that doesn't work because the model supplied by the engine is not namespaced.
So, I came up with this nightmare, which I put in app/models/tag.rb:
path = ActsAsTaggable::Engine.config.eager_load_paths.grep(/models/).first
require File.join(path, 'tag')
Tag.class_eval { include TagConcern }
But there has to be a better way! I feel like I'm missing something. I'd prefer not to add this strangeness to my app if possible.
Just require the file by looking up the path of the gem's model:
require File.join(Gem::Specification.find_by_name("bborn-acts_as_taggable_on_steroids").gem_dir, 'app/models/tag')
Tag.class_eval do
# ...
end