Reputation: 75
I have several models (User, Goal) and my Goal model has several subtypes (Exercise, Yoga, etc.)
A user can have many goals, but only one of each type.
class User < ActiveRecord::Base
has_many :goals, dependent: :destroy
has_one :exercise
has_one :water
has_one :yoga
def set_default_role
self.role ||= :user
end
end
and
class Goal < ActiveRecord::Base
self.inheritance_column = :description
belongs_to :user
validates :user_id, presence: true
validates :description, presence: true
end
where a subclass of goal is just something like this
class Exercise < Goal
belongs_to :user
end
I want to create all types of goals in my goal controller and have it set up so that localhostL:3000/waters/new will be my "water goal-type" creation page. I'm having trouble correctly setting it up though so that description is automatically set (my STI column) because I also want to build it through my user (so user_id is also set).
my goals controller currently looks like this...
def create
@goal = current_user.goals.build
???? code to set goal.description = subtype that the request is coming from
respond_to do |format|
if @goal.save
format.html { redirect_to @goal, notice: 'Goal was successfully created.' }
format.json { render action: 'show', status: :created, location: @goal }
else
format.html { render action: 'new' }
format.json { render json: @goal.errors, status: :unprocessable_entity }
end
end
end
I'm pretty new to rails so a little bit confused. Also using Rails 4.0
Upvotes: 1
Views: 239
Reputation: 774
In that case you'd need to communicate the type to create to the controller somehow.
This is most easily established by including a hidden field in the form which has a value of the type you want to create.
Assuming your block variable for the form is f
<%= f.hidden_field :type, :value => "Excercise" %>
Then you can build a goal like this:
current_user.goals.build(type: params[:type])
You can easily see how this can be very dangerous, you should always be doubly careful when using user submitted data.
To guard against a malicious user, you could set a constant in your controller
AcceptedModels = ["Excercise", "Yoga", "Water"]
def accepted_type
(AcceptedModels & params[:type]).first
end
If you also want to hide your internal structure, you could use a hash and send any identifier
AcceptedModels = {"0": "Excercise", "1": "Yoga", "2": "Water"}
def accepted_type
AcceptedModels.fetch(params[:type], nil)
end
in either case you can then build your goal like this:
current_user.goals.build(type: accepted_type)
The biggest downside with this is that you will have to keep the AcceptedModels
updated whenever you add/remove more goals
Upvotes: 1