1
votes

I have two classes "Person" and "Group" which are derived from a base class "Entity" via Rails Single Table Inheritance pattern. This pattern has DRYed up a lot of my code.

Entity itself has no relations (e.g. has_many) but Person and Group have their specific ones.

Continuing the process of simplifying my code, any changes to a person or group object are PUT against /entities/:id, triggering the update action.

Enter the problem: Rails uses attr_accessible and the relations a class has to build the params[:entity] object. Since certain things I may PUT (like operator_attributes, specific to Group) only appear in Group but not Entity, Rails does not include these in params[:entity].

How can I work around this problem while still using the Entity controller and without having to rewrite the Rails logic for building up params[:entity]?

2

2 Answers

0
votes

I came up against this same issue. My subclassed models acted differently enough that I ended up creating thin controllers to go along with my thin models. They each had different validation requirements. I couldn't just create a generic Entity object and set the type attribute during a PUT. I had to create the right kind of object.

Clearly that's not as DRY as you want, and it wasn't for me either. But in my case, I still use the Entity controller/model in the admin panel just so I can show entries and do basic reporting. On the user-facing side, they are separate and Entity is protected. They are used in different contexts, with different logic and views. So for me it ended up being the right decision to use separate controllers and views for each subclassed model.

The main thing that STI does for me is DRY up my database and my models. If the inherited models behave and display in the same way, it becomes easier to DRY up more than that. Hope this helps in some way.

0
votes

I ended up getting around this by disabling wrap_parameters for the EntityController, and creating the root entity key in the original PUT request on the client side.

If the method "attribute_names" exists on the model, it will call that, so I suppose the base Entity model could use .constantize() or some other method to figure out what to do properly.

The best solution would be for wrap_parameters to re-initialize the params hash programmatically. It looks like this is almost possible: you can change wrap_parameters but I haven't figured out how to re-process the params.

See: http://edgeapi.rubyonrails.org/classes/ActionController/ParamsWrapper.html#method-i-process_action