Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A rails field that is an array of JSON objects?

I have a Damage table that has the following fields:

  • description
  • date_of_damage

I'd like to add another field to store Damagepoints, which are JSON objects that look like this:

{ top: 50, left: 100 }

Top and left are the coordinates of the damagepoint on a diagram. The damagepoints are added/removed by the user using Javascript.

However, I'd like to store, in one field, an array of these damagepoints, like this:

@damage.damagepoints = [{left: 40, top: 99}, {left: 100, top: 35}, {left: 150, top: 95}]

I don't want to do this using a Damagepoint table with a has_many relationship because all of the changes to this will be done using Javascript, and if Damagepoints are created or removed by the user, I just want to pass from the client the updated array of damagepoints and replace the old one in the database with the new array. If I used a has_many relationship, I'd have to delete all of the Damagepoints and create each one new every time the array was updated (because it is too complicated and there is no benefit from deleting/adding specific damagepoints, as I don't need to track history).

What is the easiest way to store data like @damage.damagepoints (above)? All I need to do with it is pass it (via the controller) to an html5 data-attribute so that it can be used by the Javascript to add the existing damagepoints to the diagram (based on their coordinates) and then pass an updated array (from the html5 data-attribute) back to the controller via an AJAX call when the user clicks the 'Save' button.

I am using Rails 4.2 and Postresql.

Thanks!

like image 751
jackerman09 Avatar asked Jan 06 '23 10:01

jackerman09


2 Answers

As you're using postgres, you're in luck: postgres has a native json type. This is way better than using serialize to store the data as some form of encoded string, because postgres has a rich family of operators that allow you to query against that json data.

If you are using postgres 9.4 then you can also use the jsonb type. This is generally better as it stores a processed version of the data (i.e. it doesn't have to keep reparsing the data over and over again) and it allows indexes.

Rails supports this out of the box (see here), you just need to add a column of type json(b). If your migration contains

create_table :damages do |t|
  t.string :description
  t.jsonb :damage_points
end

then

Damage.create(damage_points:  [{left: 40, top: 99}, {left: 100, top: 35}])

would create a row with the damage points data store as json. The only thing to watch out for is that although your input data has symbols as the keys in the hashes, when fetching from the database you'll always get strings back as keys.

like image 148
Frederick Cheung Avatar answered Jan 15 '23 05:01

Frederick Cheung


Serialize your data before writing to the database and deserialize when reading. You can override the getter and setter in the model.

Two good options for serialization would be JSON and YAML.

Rails comes with the json gem so you can just call to_json on any object or array. Then you need to read it, JSON.parse(some_json).

Similarly, Rails comes with yaml so you can use YAML.dump(text) and YAML.load(text). YAML is a little more human-readable than JSON in my opinion, but if you're passing the data to Javascript, JSON is the standard.

like image 42
max pleaner Avatar answered Jan 15 '23 04:01

max pleaner