Rails secrets.yml with values containing newlines - ruby-on-rails

Let's assume I have a config/secrets.yml file that contains:
development:
app_name: MyApp
secret: <%= ENV['SECRET_VALUE'] %>
If I set SECRET_VALUE with a newline, it will break. E.g:
export SECRET_VALUE=$(printf "hello\nworld")
Then when I start my rail application I get this error:
/usr/local/lib/ruby/3.0.0/psych.rb:457:in 'parse': (<unknown>): could not find expected ':' while scanning a simple key at line 4 column 1 (Psych::SyntaxError)
While debugging the issue, I realized that the literal value of ENV['SECRET_VALUE'] is added to the yaml file before parsing it. That means if I wanted to achieve what I'm trying to do, I would have to do something like:
export SECRET_VALUE=$(printf "|\n hello\n world")
This works but this is very ugly and I can't be the only one who think this behaviour is absurd?? Is there a better way to do this?
EDIT:
I tried adding quotes around the value:
development:
app_name: MyApp
secret: "<%= ENV['SECRET_VALUE'] %>"
It "works" but the newline gets removed from the string...
root#4e4431bae32e:/app# rails console
Loading development environment (Rails 7.0.3)
irb(main):001:0> puts ENV['SECRET_VALUE']
hello
world
=> nil
irb(main):002:0> puts Rails.application.secrets[:secret]
hello world
=> nil
It's important that the newline remains for my use case.

You can use an escaped quoted string. YAML's string format is similar enough to a superset of Ruby's for String#dump to work:
development:
app_name: MyApp
secret: <%= ENV['SECRET_VALUE'].dump %>

Related

Ruby double pipe usage

I have a file which have different paths for remote server and local server.
Remote server path:
"/app/public/front-end/public/JSONModels/IdPairing/Text.json"
Local server path:
"public/front-end/public/JSONModels/IdPairing/Text.json"
I basically wanna make sure my app finds correct path for the file regardless of which server I'm at.
So I found something like double pipe ( || ) in Ruby syntax like below:
File.read("/app/public/front-end/public/JSONModels/IdPairing/Text.json" || "public/front-end/public/JSONModels/IdPairing/Text.json")
But it seems like it only reads the first path. How do you make sure it reads the second path if the file is not being found in the first path?
Thanks
A lazy way is:
begin
File.read("/app/public/front-end/public/JSONModels/IdPairing/Text.json")
rescue
File.read("public/front-end/public/JSONModels/IdPairing/Text.json")
end
Why it doesn't work for you:
irb(main):001:0> File.read("some made up name")
Errno::ENOENT: No such file or directory - some made up name
from (irb):1:in `read'
from (irb):1
from /usr/bin/irb:12:in `<main>'
irb(main):002:0> File.read("some made up name" || "Gemfile")
Errno::ENOENT: No such file or directory - some made up name
from (irb):2:in `read'
from (irb):2
from /usr/bin/irb:12:in `<main>'
As you can see, when you try to read a file that doesn't exist, Ruby explodes.
That's what exist? is for.
What you should do
irb(main):003:0> filename = File.exist?("some made up name") ? "some made up name" : "Gemfile"
=> "Gemfile"
irb(main):004:0> File.read(filename)
That's one way to do it, at least.
I would suggest to put those paths into an environment specific config file. Take a look at railsconfig/config on GitHub.
After you have installed the gem, you can add a configuration to config/settings/<RAILS_ENV>.yml like
json_file: /app/public/front-end/public/JSONModels/IdPairing/Text.json
where <RAILS_ENV> can be development, test, production or a custom environment.
And in your code, just
File.read(Settings.json_file)
If you want to try these in sequence, define a list first:
FILES = [
"/app/public/front-end/public/JSONModels/IdPairing/Text.json",
"public/front-end/public/JSONModels/IdPairing/Text.json"
]
Then you can simply open the first one that exists:
path = FILES.find { |f| File.exists?(f) }
File.open(path)
The problem was that "string" || "string" will never work, the first string is logically true and the rest is irrelevant and ignored.

Rails: Unable to use new `config/secrets.yml`

Anybody know how to set ENV variables in production.rb using the new secrets.yml?
I'm getting key: wrong number of arguments (0 for 1) for the below:
production.rb:
# DOES NOT WORK
ENV["SOME_STUFF_KEY"] = Rails.application.secrets.some_stuff.key
ENV["SOME_STUFF_SECRET_KEY"] = Rails.application.secrets.some_stuff.secret_key
# NOTE THAT THIS WORKS:
# ENV["SOME_STUFF_KEY"] = "abcdefg";
# ENV["SOME_STUFF_SECRET_KEY"] = "123456789123456789";
secrets.yml:
production:
some_stuff:
key: abcdefg
secret_key: 123456789123456789
I haven't found any information about nesting like you did with some_stuff. The release notes and all other blog posts just use flat keys as an example:
development:
secret_key_base: 3b7cd727ee24e8444053437c36cc66c3
some_api_key: SOMEKEY
Rails.application.secrets.some_api_key returns SOMEKEY in the development environment.
That's why someone created the dot_secrets gem ("Enable dot syntax on nested Rails.application.secrets")
To get nested values like yours you need to use this syntax.
Rails.application.secrets.some_stuff[:secret_key]

gsub! not doing anything in rails rake task

I'm trying to import a csv file into my database and after hours of fun I've pinpointed what the problem is: the remarks field sometimes has quotes in it and if I replace \" with \"" then the field gets imported no problem.
I've written a rake task to import the csv file and use gsub to replace \" with \"" but gsub isn't doing anything. Here's the rake task with the complete code:
csvproperty.rake
require 'csv'
task :csv_to_properties => [:environment] do
CSV.foreach("lib/assets/wp_realty_listingsdb.csv", :headers => true) do |row|
row[remarks=23].gsub!(/\"/, '\""')
Property.create!(row.to_hash)
end
end
The remarks field is the 23rd column (starting counting from 0), but I've tried it with 22 and 24 with no luck. I know this code works because I used the exact same rake task on another app using gsub to remove a comma from a price field and it worked fine, why isn't it replacing \" with \""?
EDIT:
For example, the remarks for this property on line 8 of the csv file are:
"THIS HOME EPITOMIZES THE VERY ESSENCE OF A PERFECT \"10\"."
The csv tried to escape the quotes by doing \" but it's not enough, it needs to be \"" because if I run this command:
rake csv_to_properties
then I get the following error:
rake aborted!
Missing or stray quote in line 8
But if I manually change it to \"" then the error moves on to the next line that has quotes:
rake aborted!
Missing or stray quote in line 24
But if I don't change it manually and rely on gsub to make the change the error message remains on line 8. Why isn't gsub replacing \" with \""?
Try:
> s = "THIS HOME EPITOMIZES THE VERY ESSENCE OF A PERFECT \"10\"."
> puts s
=> THIS HOME EPITOMIZES THE VERY ESSENCE OF A PERFECT "10".
> s.gsub!(/(\")/, '\""')
=> "THIS HOME EPITOMIZES THE VERY ESSENCE OF A PERFECT \\\"\"10\\\"\"."
> puts s
=> THIS HOME EPITOMIZES THE VERY ESSENCE OF A PERFECT \""10\"".

Rails 3 / Ruby error in view : couldn't parse YAML at line 20 column 14

I get this error in view: couldn't parse YAML at line 20 column 14
Here:
Rails internationalisation help
And here:
Rails 3 simple form error : couldn't parse YAML
How do I fix it?
You most likely did not end put a whitespace at the end of your YAML file.
Putting the Quotes fixed my error:
couldn't parse yaml at line 18
Put the password in config/database.yml into quotes
username: dbadmin
password: "?!?!?pass?!?!?word?!?!"

Rails 2.3.2/Ruby 1.8.6 Encoding Question - ActionController returning UTF-8?

I have a pretty simple Rails question regarding encoding that I can't find an answer to.
Environment:
Rails 2.3.2/Ruby1.8.6
I am not setting any encoding options within the Rails environment currently, have left everything to defaults.
If I read a String from disk from a text file - and send it via Rails render :text functionality using Apache/Phusion, what encoding should the client expect?
Thank you for any answers,
Since about Rails 1.2, Rails sets Ruby 1.8's $KCODE magic variable to "UTF8". It includes ActiveSupport::CoreExtensions::String::Multibyte to patch around issues with otherwise ambiguous per-character/per-byte operators. Your text file should be UTF-8, Ruby will pass it through and your application layout should specify a META tag declaring the document's charset to be UTF-8 too:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
Then it should all 'just work', but there are some gotchas described below.
If you're on a Mac, running "script/console" in Terminal.app and then pasting unusual character sequences directly into the terminal from e.g. the Character Viewer is a good way to play around and demonstrate this to your own satisfaction, since the whole OS works in UTF-8. I don't know what the equivalent would be for Windows or an arbitrary Linux distribution.
For example, "⇒" - RIGHTWARDS DOUBLE ARROW - is Unicode 21D2, UTF8 0xE2 (226), 0x87 (125), 0x92 (146). If I paste that into Terminal and ask for the byte values I get the expected result:
>> $KCODE
=> "UTF8"
>> "⇒"
=> "\342\207\222"
>> puts "⇒"
⇒
...but...
>> "⇒"[0]
=> 226
>> "⇒"[1]
=> 135
>> "⇒"[2]
=> 146
>> "⇒"[3]
=> nil
Note how you're still getting byte access with "[]". See the documentation on the Multibyte extensions in the Rails API (for Rails 2.2, e.g. at http://railsapi.com/) if you want to do string operations, otherwise things like "foo.reverse" will do the wrong thing; "foo.mb_chars.reverse" gets it right by using the "mb_chars" proxy.

Resources