1

I have a model which contains an attribute that is a serialized hash of 'settings'.

These settings will usually be empty, which is why I don't create a has_many association, but in some cases the user will want to fill these in. It should accept an arbitrary number of key/value pairs, like so:

object.settings = { first_setting: 'My setting', second_setting: 'Something else' }

The number of settings is undefined, as well as their values and names. Completely up to the user.

Ideally I'd like something along the lines of nested_form's link_to_add functionality which allows you to add a row of textfields for a new setting, one for the name of the setting and one for its value.

Other than the 'serialize :settings, Hash' in my model I've gotten just about nowhere.

Any help is much appreciated

HannesFostie
  • 475
  • 2
  • 5
  • 16
  • You may want to take a look at this post http://stackoverflow.com/questions/9613208/serialized-hash-field-and-simple-form – Pierre-Louis Gottfrois Jun 24 '13 at 13:55
  • @Pierre-LouisGottfrois sadly this doesn't help me much. The solution provided is aimed at cases where you know which keys the hash will contain, whereas I need the user to be able to specify the number and name of keys in the hash – HannesFostie Jun 24 '13 at 13:57
  • I think you'll have to get around this issue by dealing with some meta programing. You could iterate over each key in your hash and display the appropriate fields to your user. But to get the nested_forms working, I think the way to go is to somehow have an object representation of your hash. Just a thought. – Pierre-Louis Gottfrois Jun 24 '13 at 14:01
  • @Pierre-LouisGottfrois pointers are much appreciated, because I'm pretty much clueless on how to do that – HannesFostie Jun 24 '13 at 14:06

1 Answers1

1

Alright, here is what I tried and it is working quite well.

User model - models/user.rb

class User < ActiveRecord::Base
  serialize :settings

  attr_accessible :email, :settings_attributes

  def settings_attributes=(attributes)
    self.settings = attributes
  end
end

User controller - controllers/users_controller.rb

class UsersController < ApplicationController
  def index
    @users = User.all
  end

  def show
    @user = User.find(params[:id])
  end

  def edit
    @user = User.find(params[:id])
  end

  def update
    @user = User.find(params[:id])
    if @user.update_attributes(params[:user])
      redirect_to users_path
    else
      render :new
    end
  end
end

User edit page - views/users/edit.html.erb

<h1>Users#edit</h1>

<%= form_for @user do |f| %>

  <%= f.fields_for :settings_attributes, OpenStruct.new(@user.settings) do |builder| %>

    <% @user.settings.keys.each do |key| %>

      <%= builder.text_field key.to_sym %><br />

    <% end %>

  <% end %>

  <%= f.submit %>

<% end %>

When updating the user, the controller receive in the params hash a key named settings_attributes. By defining a setter in our User model, we are able to edit the serialized settings attribute.

In the view we are simply looping on all the keys in the settings hash and display a textfield. You may want to display other thing such as textarea or even select. This would require to customize the settings hash in order to know what is the type of the setting you want to display (you could store a key named type in the hash which hold the type of the setting and a key value which holds the name of the setting)

Regarding the add_new_link functionality, you may want to take a look at this railscast http://railscasts.com/episodes/196-nested-model-form-revised

I fired a rails application from scratch and it's working quite well. Let me know if you have any questions.

Pierre-Louis Gottfrois
  • 17,561
  • 8
  • 47
  • 71
  • this looks great, going to give this a go tomorrow. What about adding new keys though? You'd have to construct a new key/value pair that's empty on initialization somehow. Perhaps using a hidden field to set the key using the value in the first of the two new textfields? – HannesFostie Jun 24 '13 at 18:06
  • this could be done using HTML and JS yes. Or you could do something more complexe but more powerful using a model name `Setting` and a `User` `have_many :settings`. This way you could do everything using the nested_forms behavior. Even if you are saying that the settings are most of the time empty, it could be a better idea to implement such relation. – Pierre-Louis Gottfrois Jun 24 '13 at 20:52
  • Ended up going back to an association after all. I'll mark your reply as the answer as it's the closest I've gotten. It would have become too much work to mimick nested_form behaviour. – HannesFostie Jun 26 '13 at 08:00
  • yes, going for an association is a good call ;) Thx for marking my answer. – Pierre-Louis Gottfrois Jun 26 '13 at 11:40