How does column_fallback work?
I've added the line column_fallback to the initializer and set in the model something like:
extend Mobility
translates :title, type: :string, column_fallback: true
[2] pry(main)> b.title
=> "Ecologia polĂtica"
[3] pry(main)> Mobility.locale = :en
=> :en
[4] pry(main)> b.title
Mobility::Backends::ActiveRecord::KeyValue::StringTranslation Load (0.3ms) SELECT "mobility_string_translations".* FROM "mobility_string_translations" WHERE "mobility_string_translations"."translatable_type" = $1 AND "mobility_string_translations"."key" = $2 AND "mobility_string_translations"."translatable_id" = $3 [["translatable_type", "Blox"], ["key", "title"], ["translatable_id", 21342]]
=> nil
In config/initializers/mobility.rb inside the Mobility.configure block add:
column_fallback true
Related
This question already has answers here:
Ruby 'pass by value' clarification [duplicate]
(3 answers)
Closed 4 years ago.
Given the following two methods:
[53] pry(main)> def my_method
[53] pry(main)* leti = 'leti'
[53] pry(main)* edit(leti)
[53] pry(main)* leti
[53] pry(main)* end
=> :my_method
[54] pry(main)> def edit(a_leti)
[54] pry(main)* a_leti.gsub!('e', '3')
[54] pry(main)* a_leti
[54] pry(main)* end
=> :edit
[55] pry(main)> my_method
=> "l3ti"
Can someone explain why I am getting the value edited inside the edit method and not the original value ('leti'). I though Ruby was passed by value. In fact, if instead of using the function gsub I use a simple assignment, I get the original value. Does the gsub! make it by reference?
Thank you!
In Ruby: Objects like strings are passed by reference. Variables with objects like strings are in fact references to those strings. Parameters are passed by value. However, for strings, these are references to those strings.
So here is the classic example:
irb(main):004:0* a = "abcd"
=> "abcd"
irb(main):005:0> b = a
=> "abcd"
irb(main):006:0> b << "def"
=> "abcddef"
irb(main):007:0> a
=> "abcddef"
irb(main):008:0> b
=> "abcddef"
If you do not wish to modify the original string, you need to make a copy of it:
Three ways (of many) to do this are:
b = a.dup
b = a.clone
b = String.new a
Using dup
irb(main):009:0> a = "abcd"
=> "abcd"
irb(main):010:0> b = a.dup
=> "abcd"
irb(main):011:0> b << "def"
=> "abcddef"
irb(main):012:0> a
=> "abcd"
irb(main):013:0> b
=> "abcddef"
BTW: For myself, this effect is the number one cause of defects in my own code.
I have a string which is passed as a parameter to a function. Here, I want to check if the string contains only numbers. So I had a check like below:
def check_string(string)
result = false
if string.to_i.to_s.eql? string
result = true
end
result
end
But the problem arises when a string starts with 0. In that case, a false is returned.
check_string('123') #=> true
check_string('0123') #=> false
How can I solve this issue?
You can try the following
def check_string(string)
string.scan(/\D/).empty?
end
It would be truthy if string contains only digits or if it is an empty string. Otherwise returns false.
A number can be negative, or a float. So if these are allowed, consider this solution:
def is_numberic?(str)
str == "#{str.to_f}" || str == "#{str.to_i}"
end
some input which evaluate to true
pry(main)> is_numberic? '5'
=> true
pry(main)> is_numberic? '58127721'
=> true
pry(main)> is_numberic? '58127721.737673'
=> true
pry(main)> is_numberic? '0'
=> true
pry(main)> is_numberic? '1818'
=> true
pry(main)> is_numberic? '0.1'
=> true
pry(main)> is_numberic? '0.0'
=> true
pry(main)> is_numberic? '11.29'
=> true
pry(main)> is_numberic? '-0.12'
=> true
pry(main)> is_numberic? '-29'
=> true
the input which evaluate to false
pry(main)> is_numberic? '10 years'
=> false
pry(main)> is_numberic? '01'
=> false
pry(main)> is_numberic? '00'
=> false
pry(main)> is_numberic? '0.10'
=> false
pry(main)> is_numberic? ''
=> false
As you can see, there're several cases which probably should be supported, eg '0.10', but are not. In this case, the permitted input is '0.1'.
def check_string(str)
str !~ /\D/
end
check_string '123'
#=> true
check_string ''
#=> true
check_string '1a2'
#=> false
this is my proposition for detecting if it's a float number
def check(string)
scan = string.scan(/\D/)
scan.size == 0 || (scan.size == 1 && scan.first == ".") # or "," depend on your separator
end
example of use:
check("123") => true
check("12.3") => true
check("12e3") => false
check("12.3.2") => false
EDIT: 2023
After some years i see this is the most compact solution:
def check_string(str)
str.scan(/\D/).empty?
end
You can use Regexp for it:
def check_string(string)
raise 'Empty string passed' if string.empty?
/\A\d+\z/ === string
end
check_string '123'
#=> true
check_string '0123'
#=> true
check_string '0'
#=> true
We can also use the "match" function to do this.
"1234".match(/\D/)
#=> nil
"1234foo".match(/\D/)
#=> #<MatchData "f">
match (String) - APIdock
I think we should use the regex to find this.
it will work for the below scenarios
"3.0"
"av3"
"3"
is_numeric = false if option.option.match?(/[^0-9.]/)
If anyone is searching for another way to determine if string is numeric -> is to use "is_a? Numeric". Is_a? reference documentation
"namaste".is_a? Numeric
=> false
6.is_a? Numeric
=> true
str1 = "foo"
str2 = 9
str1.is_a? Numeric
=> false
str2.is_a? Numeric
=> true
You can also use:
7.is_a?(Numeric)
=> true
"too".is_a?(Numeric)
=> false
Basically it's determining if a class is a type of class object. I just found this and thought I would share.
Suppose I have a simple class
class Person
attr_accessor :name
def say
puts name
end
end
Is there a way to serialize it to JSON and back and get instance of the same class?
For example I would like to have a code like
p = Person.new
p.name = 'bob'
json = JSON.serialize p
# json should be smth. containing { 'name' : 'bob' }
# and maybe some additional information required for later deserialization
p2 = JSON.deserialize
p2.say
# should output 'bob'
I tried as_json (from ActiveSupport I guess), but result is {'name': 'bob'} and obviously type information is lost and after deserialization I just have a hash, not a Person instance.
Ruby's JSON library supports the Marshal interface. Short answer: you need to define #to_json and self#json_create in your class.
The trick is that you need to store the name of the class you want to round-trip back to in the json itself; the default place to do this is as the value of the key json_class and there's likely no reason to change it.
Here's a ridiculously simple example:
require 'json'
class A
attr_accessor :a,:b
def initialize(a,b)
#a = a
#b = b
end
def to_json(*a)
{
"json_class" => self.class.name,
"data" => {:a => #a, :b=>#b}
}.to_json(*a)
end
def self.json_create(h)
self.new(h["data"]["a"], h["data"]["b"])
end
end
Then you can round-trip it with JSON.generate and JSON.load. Note that JSON.parse will not work; it'll just give you back the expected hash.
[29] pry(main)> x = A.new(1,2)
=> #<A:0x007fbda457efe0 #a=1, #b=2>
[30] pry(main)> y = A.new(3,4)
=> #<A:0x007fbda456ea78 #a=3, #b=4>
[31] pry(main)> str = JSON.generate(x)
=> "{\"json_class\":\"A\",\"data\":{\"a\":1,\"b\":2}}"
[32] pry(main)> z = JSON.load(str)
=> #<A:0x007fbda43fc050 #a=1, #b=2>
[33] pry(main)> arr = [x,y,z]
=> [#<A:0x007fbda457efe0 #a=1, #b=2>, #<A:0x007fbda456ea78 #a=3, #b=4>, #<A:0x007fbda43fc050 #a=1, #b=2>]
[34] pry(main)> str = JSON.generate(arr)
=> "[{\"json_class\":\"A\",\"data\":{\"a\":1,\"b\":2}},{\"json_class\":\"A\",\"data\":{\"a\":3,\"b\":4}},{\"json_class\":\"A\",\"data\":{\"a\":1,\"b\":2}}]"
[35] pry(main)> arr2 = JSON.load(str)
=> [#<A:0x007fbda4120a48 #a=1, #b=2>, #<A:0x007fbda4120700 #a=3, #b=4>, #<A:0x007fbda4120340 #a=1, #b=2>]
This is my code:
[164] pry(main)> h = Hash.new "A"
=> {}
[165] pry(main)> h["x"]
=> "A"
[166] pry(main)> h["x"] = "XXX"
=> "XXX"
[167] pry(main)> h["x"]
=> "XXX"
[168] pry(main)> h["y"].downcase!
=> "a"
[169] pry(main)> h["y"]
=> "a"
[170] pry(main)> h["z"]
=> "a"
[171] pry(main)>
As you can see, I can create a hash h with a default value A. After h has been created, I can change this default value to its downcase!, which is a. Here my question is, how can I change it to arbitrary value, like "xyz". Apparently I can't use something like h["not-exist"] = "xyz";, as that will create the new key with the value.
You can use Hash#default= to set the default value.
h = Hash.new "A"
#=> {}
h.default = "xyz"
#=> "xyz"
h["non-exist"]
#=> "xyz"
While working through http://docs.basho.com/riak/latest/dev/taste-of-riak/querying-ruby
I noticed what I can't store Time object in riak for some reason.
[3] pry(main)> client = Riak::Client.new(:protocol => "pbc", :pb_port => 8087, :host => "192.168.145.34")
=> #<Riak::Client [#<Node 192.168.145.34:8098:8087>]>
[4] pry(main)>
[5] pry(main)>
[6] pry(main)> tt = client.bucket('test')
=> #<Riak::Bucket {test}>
[7] pry(main)> v = tt.new("ttt")
=> #<Riak::RObject {test,ttt} [#<Riak::RContent [application/json]:nil>]>
[8] pry(main)> v.data = 1
=> 1
[9] pry(main)> v.store
=> #<Riak::RObject {test,ttt} [#<Riak::RContent [application/json]:1>]>
[10] pry(main)> v.data = Time.now
=> 2014-06-22 11:34:01 +0400
[11] pry(main)> v.store
SystemStackError: stack level too deep
from /home/maus/.gem/ruby/1.9.1/gems/pry-0.10.0/lib/pry/pry_instance.rb:353
After that I discovered what it's the case for user defined classes too:
[16] pry(main)> class Tst
[16] pry(main)* def initialize(x)
[16] pry(main)* #x = x
[16] pry(main)* end
[16] pry(main)* end
=> nil
[17] pry(main)> t111 = Tst.new(111)
=> #<Tst:0x9b13f4c #x=111>
[18] pry(main)> v.data = t111
=> #<Tst:0x9b13f4c #x=111>
[19] pry(main)> v.store
SystemStackError: stack level too deep
from /home/maus/.gem/ruby/1.9.1/gems/pry-0.10.0/lib/pry/pry_instance.rb:353
[20] pry(main)>
[21] pry(main)> v.data = [1,2,3]
=> [1, 2, 3]
[22] pry(main)> v.store
=> #<Riak::RObject {test,test_key} [#<Riak::RContent [application/json]:[1, 2, 3]>]>
Looks like something is terribly wrong with my install. But how to investigate it? I'm using riak-1.3.2 and ruby 1.9.3p194 with the following versions of gems:
i18n-0.6.9
builder-3.2.2
beefcake-0.3.7
multi_json-1.10.1
innertube-1.0.2
riak-client-1.4.4.1
The only place in the store method code path were I see the value being use is in BeefcakeProtobuffsBackend.ObjectMethods::dump_object which instantiates an RpbContent with :value => maybe_encode(robject.raw_data), so this would appear to be an issue with serializing the custom data.
RContent.raw_data calls Serializers::serialize
def serialize(content_type, content)
serializer_for(content_type).dump(content)
end
Serialize only understands a very few content types:
Serializers['text/plain'] = TextPlain
Serializers['application/json'] = ApplicationJSON
Serializers['application/x-ruby-marshal'] = ::Marshal
The default for content_type is application/json, whose dump method is:
def dump(object)
object.to_json(Riak.json_options)
end
Check that v.raw_data returns the value you expect, and if not, try setting v.content_type='text/plain'
For your custom class, make sure it has a to_json or to_s method that returns a string, and select the appropriate content_type.