How to edit a serialized hash column in form textarea

独自空忆成欢 提交于 2020-01-03 16:22:25

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!