Where/How do i need to set global variable to be accessed throughout all the models - rhomobile

I have login section when my apps start. So i need to keep trace of the user_id through out the application.
I'm getting the user_id as like below,
##user_id = #params["user_id"]
But making it a class variable don't work. As i can't access this from other class or model.
Any way to do this ?

You can make this to set it to some global variable which you can initialize in application.rb file.
application.rb
class AppApplication < Rho::RhoApplication
def initialize
$user_id ||= ""
end
end
Then on your controller, you can set it to required value.
$user_id = #params["user_id"]
That's it, now you can access this through out the application.
For details, have a look over here http://mindfiremobile.wordpress.com/2013/08/27/types-of-variables-in-rhomobile/

Related

Ruby Singletion Class

I want a HomePage model to be a Singleton class, as i want only one instance of the HomePage model. So this is what I did:
require 'singleton'
class HomePage < ApplicationRecord
include Singleton
has_one_attached :image
end
In HomePagesController, I want the users to be able to edit the unique instance of the HomePage model. So, i did something like this:
class HomePagesController < AdminDashboardsController
def edit
#home_page = HomePage.instance
end
end
Problem:
The default value that HomePage.instance returns nil. I am guessing that the instance is not persisted, as it returns false for the presisted? method call.
I want to be able to create the unique instance for the first time, i.e. override the nil instance that I get from HomePage.instance using seed data, or rails console, and then give the user the ability to edit that instance for as long as they want, using the HomePage Controller as shown in above code.
What i tried:
I tried updating the initial unique instance of the HomePage model, by calling HomePage.instance.update(name: "Hello"). This seemed to create a different instance with id:2, rather than overwriting the previous unique object.
Am I missing out on something? Or am I misunderstanding the overall use of Singleton class itself?
The problem is that singleton is about Ruby object, not about record in the database. And because of multi-threading the processes in Rails are isolated
So if you need to keep just one record don't use require 'singleton'
Define method
def self.get
first || create # more Rails way - first_or_create
end
or
def self.get
first || new # more Rails way - first_or_initialize
end
And in your code call HomePage.get

Ruby variables visibility inside modules

TL;DR;
I need to make some ##vars of a static method (extends) in one module visible to a instance method in another module(includes).
How to accomplish that once only setting ##var=value was not enough to make it visible?
Maybe you can just read my capitalized comment bellow and jump to question 4.
Hi, I would like to add an method to my models to index some data in a mysql table with some full text search fields.
In order to accomplish that, I created the following module:
module ElasticFakeIndexing
module IndexingTarget
#instance method to be called on model to get data to save
def build_index_data
{
entity_id: self.id,
entity_type: self.class.name,
#UNABLE TO ACCESS IF SET ONLY WITH ##var=value. Why?
#AND ALMOST SURE THAT USING class_variable_set IS THE CAUSE OF CONFIGURATION OF ONE MODULE MESSING UP WITH ANOTHER'S
title: ##title_fields.collect{|prop| self.send(prop.to_sym)}.join(" || "),
description: ##description_fields.collect{|prop| self.send(prop.to_sym)}.join(" || "),
}
end
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
#class method to declare/call at a given model
def elastic_fake(options = {})
#Make sure we always get an array so we can use 'join'
title_arg = Array(options[:title])
ElasticFakeIndexing::IndexingTarget.class_variable_set(:##title_fields, title_arg)
description_arg = Array(options[:description])
ElasticFakeIndexing::IndexingTarget.class_variable_set(:##description_fields, description_arg)
extra_arg = Array(options[:extra])
ElasticFakeIndexing::IndexingTarget.class_variable_set(:##extra_args, extra_arg)
end
end
end
end
And I use it this way at my models:
class SomeModel < ApplicationRecord
#includes the module
include ElasticFakeIndexing::IndexingTarget
...
# 'static' method call to configure to all classes of this model
elastic_fake(title: "prop_a", description: ["prop_b", "prop_c", "prop_d"])
end
And at some point of my code something like this will be called:
index_data = some_model_instance.build_index_data
save_on_mysql_text_search_fields(index_data)
But I got some problems. And have some questions:
when I use/include my module in a second model, looks like the configuration of one model is being visible to the other. And I got 'invalid fields' like errors. I guess it happens because of this, for example:
ElasticFakeIndexing::IndexingTarget.class_variable_set(:##title_fields, title_arg)
But I got to this this because only set ##title_fields wasn't enough to make title_fields visible at build_index_data instance method. Why?
Why using only #title_fields isn't enough too to make it visible at build_index_data?
How to design it in a way that the set of fields are set in a 'static' variable for each model, and visible inside the instance method build_index_data? Or as a possible solution, the fields could live in a instance variable and be visible. But I think it should live in a 'static' variable because the fields will not change from one instance of the model to another...
Any thoughts? What am I missing about the variables scopes/visibility?
Thank you
Read the following articles on Ruby variables:
Ruby Variable Scope
Understanding Scope in Ruby
quick reminder: ##title_fields, class variable, must be initialized at creation time, while #title_fields, instance variable, hasn't such requirement.
Instead of relying on class variables I recommend using class side instance variables. Class variables will easily be overwritten between individual models including the module. Class side instance variables however are save.
Using some of the syntactic sugar (namely concern and class_attribute) rails offers you could write something like
module ElasticFakeIndexing
extend ActiveSupport::Concern
included do
class_attribute :title_fields,
:description_fields,
:extra_args
end
class_methods do
def elastic_fake(options = {})
...
self.title_fields = Array(options[:title])
...
end
end
def build_index_data
...
title: self.class.title_fields ...
...
end
end

Storing a global variable that holds a collection of models

I want to store a global variable so I don't hit the database each time I reference the models.
Should I do this in an initializer or is there another way?
$rules = Rule.all
This data will never change unless I change the codebase so it is fine to only be refreshed when the app reloads.
What options do I have?
I think I can do this also in my controller:
$rules ||= Rule.all
Is there a "best practise" concerning this?
Ok, then inside the config/initializers/ directory create a file like load_rules.rb. And inside that, write something like:
ActiveSupport.on_load(:active_record) do
RULES = Rule.all
end
Now use this constant anywhere you want to use.
I'd suggest using low-level caching wrapped in a method:
class ApplicationCotroller < ActionController::Base
# ...
def all_rules
Rails.cache.fetch("all_rules") do
Rule.all
end
end
# ...
end
Depending on your use case the method could be placed in a singleton class instead of ApplicationController or in a mixin Module.
The main benefit of this approach is you can easily reload the rules without restarting the server by deleting the cache key from the console. Although you clearly marked this as a non-critical aspect, I think it adds some convenience.
I think you don't want to use the database for such a thing. You should store these values as an array of objects and use the Rails.app.config.x namespace:
so your model would look like:
#app/models/rule.rb
class Rule
attr_reader :name
def initialize(name:)
#name = name
end
end
and your initializer:
# config/initializers/rules_initializer.rb
Rails.application.config.x.rules = [
Rule.new(name: "Admin"),
...
]

How to include session in my custom lib file?

I know I will get answers that I shouldn't do this, but due to specific way to solve problem I am facing, I will have to use session in my /lib/example.rb file. (or at least I think I will have to use it)
I am calling an action, which will first run (seudo code):
module ApplicationHelper
def funcion(value)
MyClass.use_this(value)
end
end
And then I will use it in my lib/example.rb
module MyClass
# include SessionsHelper # this is not working
def self.use_this(value)
# I want to be able to use session here. What I need to do that in order to make it work.
session[:my_value] = value
end
end
What should I do in order to use session inside MyClass (I can pass variable to MyClass.use_this(value,session), but I wouldn't want to do that
Edit:
What I want to achieve with this session thing is that I would like to preserve a value during multiple requests. I am making a call to the web application multiple times, and I want to preserve some value on the next call. I am calling the app via API and I shouldn't use database to save values. So I have left with sessions, or text files, or even maybe cookies to make this happen - to preserve the same value on multiple calls.
Why not include the module in your controller, and then call the use_this function directly from there?
module MyClass #should probably rename this anyway
def use_this(value)
session[:my_value] = value
end
end
class SomeController < ApplicationController
include MyClass
def some_action
...
use_this(the_value)
...
end
end
In order to use session inside MyClass may be you could use instance variable #session:
module MyClass
extend SessionsHelper
def self.use_this(value)
#session[:my_value] = value
end
end
module SessionsHelper
def some_method
#session = ...
end
end
self.include(module) method makes the instance methods (and instance variables) of the included module into instance methods of the including module.
Edit: include SessionsHelper changed to extend SessionsHelper
self.extend(module) -- methods of receiver become class methods of that class and instance variables will work between this methods.

Ruby on Rails - Access controller variable from model

I am trying to access an instance variable which is set in the controller in the model. The controller is the products controller and the model is the products model. The instance variable is a instance of another model called account.
The instance variable is #current_account
When I run the code nothing happens, I do not get an error. Does anyone know where I can find something read about access instance variables set in the controller from the model?
Thanks
Eef
You shouldn't generally try to access the controller from the model for high-minded issues I won't go into.
I solved a similar problem like so:
class Account < ActiveRecord::Base
cattr_accessor :current
end
class ApplicationController < ActionController::Base
before_filter :set_current_account
def set_current_account
# set #current_account from session data here
Account.current = #current_account
end
end
Then just access the current account with Account.current
DISCLAIMER: The following code breaks MVC conventions, that said...
Using class attributes can probably lead to thread safety issues. I would use Thread.current + around_filter to store controller related data at thread level, and ensure it gets cleared
just before the request finishes:
class ApplicationController < ActionController::Base
around_filter :wrap_with_hack
def wrap_with_hack
# We could do this (greener solution):
# http://coderrr.wordpress.com/2008/04/10/lets-stop-polluting-the-threadcurrent-hash/
# ... but for simplicity sake:
Thread.current[:controller] = self
begin
yield
ensure
# Prevent cross request access if thread is reused later
Thread.current[:controller] = nil
end
end
end
Now the current controller instance will be avaliable globaly during the request processing through Thread.current[:controller]
If you need to access a controller variable from a model it generally means your design is wrong because a controller serves as bridge between view and model (at least in Rails), controller gets info from models, models shouldn't know anything about controllers, but if you want to do it anyway you can do it just as jeem said, but I'd rather do:
class << self
attr_accessor :current
end
instead of cattr_accessor :current
you can see why here => cattr_accessor doesn't work as it should
I can't comment directly so I'll post here: the accepted answer does not seem to be right. As #vise notes, class variables are shared across requests. So unless there's just one current account for the entire app, this won't behave as expected.
For more, see the accepted answer by #molf here: Is Rails shared-nothing or can separate requests access the same runtime variables?
I'm not sure if I understand the question exactly, but I'll take a stab.
I think if you need to access a controller instance variable from the model then you either need to make it an attribute in the model, or move your logic to the other class controller, not model.

Resources