Search code examples
ruby-on-railsrubypostgresqlhstore

Hstore+Rails Access all the possible fields in a hstore column


Note: The formulation of this question tries to model a chronological evolution of an app. So each context is an evolution of the former one, aka following iteration with added fields/functionalities

=== Context in TIME 0

  1. I've got an application with User model. This model has an hstore column called info
  2. The column info intends to store keys ['name', 'first_surname', 'phone']. Alsostore_accessor :name, :first_surname, :phone is used.
  3. Several users are created, filling those three fields. Let's say we have 10 of these users.
  4. When I want to display the profile of the user, I do it this way:

(This renders each field of the user table in a table, including all fields within the info hstore column.)

Reference:"PROFILE SHOW"

#app/views/users/profile.html.erb
<h3>Profile</h3>

  <table class="table table-striped">
    <tbody>
      <tr><th>Email</th><th><%=current_user.email%></th></tr>
      <% unless current_user.info.nil? %>
        <% current_user.info.each do |key,val| %>
          <tr>
            <th><%=key.gsub('_',' ').titleize%></th>
            <th><%=val%></th>
          </tr>
        <% end %>
      <% end %>
    </tbody>
  </table>

=== Context in TIME 1

  1. Now I decided that for each user I want to store also city, province, passport.
  2. I am going to store those new fields as key/value pairs within the info column of User.
  3. Whenever there is a new Signup, the sign-up form presents those three fields(city,province,passport), so the user can fill them in.
  4. When I want to render the profile of a recently created user the code used in Ref."PROFILE SHOW"(see above) works well.

Question: How can I modify the code "PROFILE SHOW" so that it works also with the first 10 created User, during context TIME 0. In such a way that the page would render

|province |     |
|city     |     |
|passport |     |

I.e. blank space at those fields that did not exist in info during context TIME 0.

In other words: how does one keep track of "potential" fields in a hstore column, that is fields that exist in other instances but not in yours.

This is desirable because I would like to present them in the EDIT page too, so the user can fill the fields that did not exist before.

My approaches so far:

  • Keep all the fields in an array, and instantiate it in the controller method, and then change the "PROFILE SHOW" code:
#app/controllers/users_controller.rb
def profile
  @info_attributes=%w(name first_surname phone passport city province)
end

#app/views/profile.html.erb
<% @info_attributes.each do |key| %>
 ...
<% end %>
  • Do the same but keep that attribute array inside some kind of global variable/cache, which is read inside the controller method, and assigned to the instance variable.

thanks!


Solution

  • how does one keep track of "potential" fields in a hstore column, that is fields that exist in other instances but not in yours

    There's no direct way, because a hstore is just a key/value store as a field value. It has no relationship to any other hstore value.

    If you wish to define a list of known keys, your application must maintain that its self with a side table of possible keys, either as individual rows or as a single hstore field with each key pointing to a dummy placeholder value. I recommend individual rows for better concurrency.