to_json method in rails 2.0.2 for objects(say user model object with id and name)used to give simple output in the form
{"id":"xyz","name":"hello"}
But while upgrading the rails to 2.3.4 it gives the output as
{"user":{"id":"xyz","name":"hello"}}
This is breaking my most of the frontend code.
Is there way to get the results in the same fashion as in 2.0.2 ???
Looking for a speedy answer from you guys!!
You need to edit the file config/initializers/new_rails_defaults.rb and change ActiveRecord::Base.include_root_in_json = true to false. That should do it. See the to_json documentation.
If for some reason you don't have that file, this is what it should look like in a default Rails 2.3.x app.
# Be sure to restart your server when you modify this file.
# These settings change the behavior of Rails 2 apps and will be defaults
# for Rails 3. You can remove this initializer when Rails 3 is released.
if defined?(ActiveRecord)
# Include Active Record class name as root for JSON serialized output.
ActiveRecord::Base.include_root_in_json = true
# Store the full class name (including module namespace) in STI type column.
ActiveRecord::Base.store_full_sti_class = true
end
# Use ISO 8601 format for JSON serialized times and dates.
ActiveSupport.use_standard_json_time_format = true
# Don't escape HTML entities in JSON, leave that for the #json_escape helper.
# if you're including raw json in an HTML page.
ActiveSupport.escape_html_entities_in_json = false
Related
I work on Rails 5.2.3 and Ruby 2.5.1. At some point, I found an issue when I expected my array-of-string constant to contain some string but it didn't. Turned out the problem was related to German Umlaute characters (öäü).
So I have the constant defined like the following:
# coding: utf-8
# frozen_string_literal: true
class MyClass
module MyModule
MY_CONSTANT = [
'Breite in mm',
'Höhe in mm',
'Länge in mm'
].map(&:parameterize).freeze
end
end
I expect the constant to look like ["breite-in-mm", "hoehe-in-mm", "laenge-in-mm"]
But instead it's stored as ["breite-in-mm", "hohe-in-mm", "lange-in-mm"]. You see, "ö" has been converted to "o" instead of "oe". Same for "ä". Now it's "a", not "ae".
It works this way on production, in RSpec tests and even when I start Rails console and call this constant. But when I define a new constant from Rails console using the very same code, the strings are being successfully converted to what I expect, i.e. ["breite-in-mm", "hoehe-in-mm", "laenge-in-mm"]
I could easily get rid of this parameterize method and just type in the strings as I need them. Maybe I will have to do that. But I'm really curious about why all this is happening and couldn't find an answer by myself.
So thank you in advance for any ideas.
The parameterize method in Rails (through its use of ActiveSupport::Inflector#transliterate) is in locale aware. It thus uses locale-depending rules to transliterate characters such as Umlauts to ASCII characters.
When your app handles a request (or at least once after booting), you are usually setting a I18n locale, e.g. with I18n.locale = :de for a single request or with I18n.default_locale = :de for your whole app. After that, Rails (resp. the i18n gem) used this locale by default for its transliteration rules.
When initially setting your constant, this default locale was likely not yet set. The i18n gem is thus not aware of the German transliteration rules and uses only the basic Unicode normalization rules.
As a workaround, you can either pass the desired locale to use to the parameterize method as
MY_CONSTANT = [
'Breite in mm',
'Höhe in mm',
'Länge in mm'
].map { |const| const.parameterize(locale: :de).freeze }.freeze
or you can alternatively set the default i18n locale earlier than when your code is executed (e.g. in a file in config/initializers, depending on where exactly you initialize your constant):
I18n.default_locale = :de
Thanks, Holger Just for your great answer. It seems to be correct except it only works for Rails 6.0.0. So I'm going to post the one for Rails 5.2.3 which I'm using on my project.
Unfortunately in Rails 5 parameterize method does not accept the locale argument yet. This will be possible only in Rails 6.
But still, as mentioned in Holger Just's answer, parameterize method relies on transliterate method which does actually use current locale and converts strings according to it.
See Rails 5.2.3 docs and sources for those methods:
https://api.rubyonrails.org/v5.2.3/classes/ActiveSupport/Inflector.html#method-i-parameterize
https://api.rubyonrails.org/v5.2.3/classes/ActiveSupport/Inflector.html#method-i-transliterate
So I cannot pass the locale to parameterize method directly. Then I should set the locale before my constant is defined.
Setting I18n.default_locale = :de inside application.rb file did not help. I already had that and the strings have been transliterated regardless.
What eventually helped was setting I18n.locale = :de manually. Thanks to this, I got my strings parameterized correctly without any changes to MyConstant definition.
I have internationalized and localized my application using the standard rails mechanisms.
Everything is stored in en, fr, de.yml files.
My application is multi-tenant, based on the subdomain.
I would like to allow my users to override certain translations in the application (e.g. to change "Employee" to "Associate" because it matches their own terminology).
I've tried to change the load path of my yml files on a per-request basis, but to no avail.
Any idea how I could, for each request, look up first in my user-specific yaml file, and fall back to the default yaml file if the translation was not overriden?
Assuming you store the subdomain in an instance variable from a controller filter, you could override the translation helper to do a lookup with a subdomain-specific scope first, then fallback to the specified or default scope. Something like this:
module ApplicationHelper
def t(key, original_options = {})
options = original_options.dup
site_translation_scope = ['subdomain_overrides', #subdomain.name]
scope =
case options[:scope]
when nil
site_translation_scope
when Array
options[:scope] = site_translation_scope + options[:scope]
when String
[site_translation_scope, options[:scope]].join(".")
end
translate(key, options.merge(:scope => scope, :raise => true))
rescue I18n::MissingTranslationData
translate(key, original_options)
end
end
Then you add your subdomain-specific overrides likes this:
en:
customer: Customer
subdomain_overrides:
subdomain_1:
customer: Buyer
If you want to allow tenants to use specific language but fallback to the default, I have written a micro library that will get the job done:
https://github.com/ElMassimo/i18n_multitenant
It takes care of configuring I18n to fallback to the base locale, allowing you to use tenant-specific translations if available. It's designed to work with the default backend of static .yml files, but it should also work with other I18n backends.
I've recently created I18n_global_scope gem that does exactly what you are describing, please checkout the source code https://github.com/mobilityhouse/i18n_global_scope and let me know your feedback.
I'm using Rails 3 w/ Mongoid, (so no ActiveRecord). Mongoid uses ActiveModel's "to_json" method, and by default that method includes the root object in the JSON (which I don't want).
I've tried putting this in an initializer:
ActiveModel::Base.include_root_in_json = false
But get the error
uninitialized constant ActiveModel::Base
Any ideas how I can change this? I changed the default directly in the source-code and it worked fine, but obviously I'd like to do it properly.
The variable is defined at the top of this file:
Github - activemodel/lib/active_model/serializers/json.rb
From the docs:
"The option ActiveModel::Base.include_root_in_json controls the top-level behavior of to_json. It is true by default."
I know this is old, but another way you can do this is by placing this within your application class in application.rb:
# When JSON-encoding a record, don't wrap the attributes in a hash where the
# key is named after the model
config.active_record.include_root_in_json = false
You should simply set it on the class that includes the ActiveModel modules:
class Person
include ActiveModel::Validations
include ActiveModel::Serializers::JSON
self.include_root_in_json = false
...
end
ActiveModel::Base.include_root_in_json = false
in an initializer??
If you prefer initializers, it's ActiveRecord::Base, not ActiveModel::Base in Rails versions 2.* and 3.1, possibly 3.0. Looked through the source, and in 3.0 beta it was switched to ActiveModel, but back again to ActiveRecord at some point.
ActiveRecord::Base.include_root_in_json = false
Also, in case you're actually trying to use this functionality, in Rails 3.1 the params wrapper is relevant:
ActionController::ParamsWrapper
Wraps the parameters hash into a nested hash. This will allow clients to submit POST requests without having to specify any root elements.
http://edgeapi.rubyonrails.org/classes/ActionController/ParamsWrapper.html
If I have some config for web admin to set e.g. number of post per page, some enum showing choice. How should I keep this settings in db ? Should I serialize it and save as blob.
Thanks,
I using rails and I want it to dynamically change this setting through web interface, so I think environment.rb would not fit this situation. So I should have a extra table with two tuples as name, value ?
Most languages/frameworks have a config file of sorts. such as the web.config in ASP or the environment.rb files in RoR. You could use one of these.
Or failing that have a key value pair table in your database.
If you're wanting to do this dynamically through the website I would definitely go for the key value pair table.
For the dynamic config values, you should create a model called Configuration with keys and values. I generally have multiple value columns (for number, string, and date) and then call the appropriate method for the configuration.
For "enums" you should create lookup tables with foreign key relationships to where they attach. For example if you have a Post model and you want an enumeration of Category, you should make the Post belong_to :category and Category has_many :posts.
Use a YAML file. YAML is way simpler than XML.
Make a file called "config.yml" in "config" directory. And load the file using YAML::load(). You can make a setting for each environment by naming the first level as environment (e.g., production, development, test).
See this episode of RailsCasts for details.
If you are using asp.net you can use the Web.Config file.
See Asp .net Web.config Configuration File
You could to create a single table in your database to store key-value pairs.
This is what I use. Got the idea from elsewhere, but the implementation is mine. Pulled from a production project of mine:
class AppConfig
# Loads a YAML configuration file from RAILS_ROOT/config/. The default file
# it looks for is 'application.yml', although if this doesn't match your
# application, you can pass in an alternative value as an argument
# to AppConfig.load.
# After the file has been loaded, any inline ERB is evaluated and unserialized
# into a hash. For each key-value pair in the hash, class getter and setter methods
# are defined i.e., AppConfig.key => "value"
# This allows you to store your application configuration information e.g., API keys and
# authentication credentials in a convenient manner, external to your application source
#
# application.yml example
#
# :defaults: &defaults
# :app_name: Platform
# :app_domain: dev.example.com
# :admin_email: admin#example.com
# :development:
# <<: *defaults
# :test:
# <<: *defaults
# :production:
# <<: *defaults
# :app_domain: example.com
#
# For example will result in AppConfig.app_domain => "dev.example.com"
# when Rails.env == "development"
#
class << self
def load(file='application.yml')
configuration_file = File.join Rails.root, 'config', file
File.open(configuration_file) do |configuration|
configuration = ERB.new(configuration.read).result
configuration = YAML.load(configuration)[Rails.env.to_sym]
configuration.each do |key, value|
cattr_accessor key
send "#{key}=", value
end
end if File.exists? configuration_file
end
end
end
AppConfig.load
Create config/initializers/app_config.rb and paste the above code into it. I'm going to make this into a gem. I figure other people will find it useful.
EDIT: Just saw you wish to edit the config as the app runs via a web based interface. You could do this with this method as both getter and setter methods are defined for each attribute.
in your controller:
def update
params[:configuration].each { |k,v| AppConfig.send "#{k}=", v }
…
end
I don't find a model is the right solution here. Forget about the DB overheard, the idea of being able to instantiate something that controls app configuration doesn't make sense. What's more how you implement it? An instance for each tuple?! It should be a singleton class.
When using Warbler, what line(s) do I need to add to config/warble.rb to keep it from including Active Record in the bundled gems. I already have excluded Active Record in config/environment.rb as shown below.
config.frameworks -= [ :active_record ]
I tried the same thing only using config.gems in config/warble.rb, but to no avail.
I haven't been able to try either of these ideas, but looking at Nick Sieger's examples :-
Does the gem name have to be a String rather than a Symbol?
It looks like activerecord maybe being included implicitly because config.gems includes rails and config.gem_dependencies = true. Maybe you need to change config.gem_dependencies to false and explicitly include rails, actioncontroller, etc in config.gems.
It might be instructive to print out or log the value of config.gems from within the warble.rb file.