I've got three classes Admin
, Client
, Agent
which all inherit from User < ActiveRecord::Base
. The system is designed using STI, hence all classes share the same users
table.
I am interested in keeping the CRUD functionality pretty much the same, hence for now I am using a single UsersController
.
When implementing the Update functionality I'm faced with a doubt. Here's my edit form:
#Edit Form
<%= form_for(@user,{url:user_path(@user),method: :put}) do |f| %>
<%= render 'edit_fields',f:f %>
<%= f.submit "Save", class: "btn btn-large btn-primary"%>
<% end %>
#UsersController
def edit
@user=User.find(params[:id])
end
def update
binding.pry
#if @user.update_attributes(params[:user]) #<---BEFORE
#WORKAROUND BELOW
if @user.update_attributes(params[@user.type.downcase.to_sym])
flash[:success]="User was updated successfully."
redirect_to user_path(@user)
else
flash[:danger]="User could not be updated."
render 'new'
end
end
My "problem" is that params
is dependent on the @user.type
of the @user
instance. Therefore sometimes there's a params[:client]
, other times a params[:admin]
or params[:agent]
.
Hence the line
if @user.update_attributes(params[:user])
does not always work.
The workaround I implemented works fine, but I was wondering whether there's a more DRY or elegant way to approach these issues, i.e. sharing CRUD between different STI-ed classes.
There is indeed a much more elegant solution. Just change your form_for
declaration and add the as
option, like this:
<%= form_for(@user, as: :user, url: user_path(@user), method: :put) do |f| %>
That way in your controller your parameters will be scoped under the user
key instead of the model's class.