问题
I have a serialized column in Company model:
class Company < ActiveRecord::Base
serialize :names
Ideally I want it to store different names like this in the database:
---
short: bestbuy
long: bestbuy ltd.
Currently in my company#edit page, I have a text area for it:
<%= f.text_area :names %>
If I have that YAML in the database, it will be displayed in the browser as:
{"short"=>"bestbuy", "long"=>"bestbuy ltd."}
However when I submit it, in the database it became:
--- ! '{"short"=>"bestbuy", "long"=>"bestbuy ltd."}'
Question
How can I make it so that textarea displays YAML for editors to edit?
How to make the database save the proper YAML, not a mash of YAML and ruby hash?
update
If I force the column to be of type Hash
like this:
serialize :names, Hash
it will give error when I try to save:
ActiveRecord::SerializationTypeMismatch in Admin::CompaniesController#update
Attribute was supposed to be a Hash, but was a String
回答1:
You can muck about in the database by hand using raw SQL but I wouldn't recommend it if you don't already know what you're doing. A corollary is that you shouldn't be messing around with the database's version of the YAML unless you already know exactly what you're doing.
Instead, convert the data to YAML yourself:
@names = m.names.to_yaml
and then stuff @names
into your <textarea>
. Then to save the edited YAML, parse it back to a Hash and hand it off to your model:
m.names = YAML.parse(params[:names])
# Or modify `params` in-place
params[:name] = YAML.load(params[:names])
# then stuff `params` into `m` as usual
To be somewhat safe, you should specify that your names
should be a Hash in the model:
serialize :names, Hash
I'm not a big fan of serialize so I usually recommend that it not be used; however, if you are going to use it, you should always specify the class_name
to make it safer to use.
Your current approach is putting the to_s
version of your Hash into the <textarea>
:
{"short"=>"bestbuy", "long"=>"bestbuy ltd."}
That's a string, not a Hash; it may look like a Hash but HTML doesn't know what a Ruby Hash is so it is just a string. Then you read that back in and put it into names
which then YAMLifies (as a string) to this:
--- ! '{"short"=>"bestbuy", "long"=>"bestbuy ltd."}'
That's a string in YAML, a string that looks a lot like a Hash but a string nonetheless.
回答2:
A late answer to my own question:
class ConfigSerializer
def self.load(i)
if i.blank?
{}
else
YAML.load(i)
end
end
def self.dump(i)
i = {} if i.blank?
if i.is_a?(String) # Allow assigning an YAML string as input
i
else
YAML.dump(i)
end
end
end
and in the model
serialize :names, ConfigSerializer
This way I can assign a YAML string and it will be stored into the database as is. Only when it is loaded from database it is converted to hash object.
In view I set textarea to have the raw YAML string, so user can edit it.
回答3:
Try to store the names into db like :
names = HashWithIndifferentAccess.new({"short"=>"bestbuy", "long"=>"bestbuy ltd."})
company = Company.new
company.names = names.to_yaml
hope, it will help .
来源:https://stackoverflow.com/questions/10345054/how-to-edit-a-serialized-hash-column-in-form-textarea