How and where should I implement this?
I have a Service model with title:string description:string date:datetime. I would like to implement a system to create multiple services based on date patterns, e.g. when the user create a new service for Oct 20 he can choose to "repeat" it once a month for 5 months. The final result should be that 6 services开发者_JAVA技巧 are created, due to Oct 20, Nov 20, etc. The way I implemented this is working, but really ugly. I have something like this in my view:
<input type="radio" name="each" value="none" checked="true"/>No<br/>
<input type="radio" name="each" value="week"/>Each week for <input type="text" name="weeks_number" /> weeks.<br/>
<input type="radio" name="each" value="month"/>Each month for <input type="text" name="months_number" /> months.<br/>
In my controller, I calculate the dates the various services will take place, than create N Service objects (where N is the number specified in params[:weeks_number] or params[:months_number]) and save each of them.
This doesn't sound good, does it? First of all, I was thinking about moving all the logic for creating "multiple" services into the model. The next big thing is: how to clean up the view and the controller? I'd like my controller to be as simple as
@service = Service.new(params[:service])
In order to do this I'll have to change something in the model (this should be called virtual attributes) in order to let the controller believe that something like
@service.repeat_method = "month"
@service.repeat = 6
actually makes sense and will cause the creation of 6 different rows in my db, when calling @service.save.
Here is where I'm stuck and in need of help. Does my reasoning make any sense? And how to implement this?
Thank you.
I wouldn't have the repeat_method
and repeat
attributes on a Service instance doing the magic you describe in the question. I'd have a create_repeats
method something like this:
# Create repeats of this Service
# how_many:: the number of repeats to create
# repeat_method:: whether to repeat 'weekly' or 'monthly'
def create_repeats(how_many, repeat_frequency)
# Set the first thing to be cloned as this instance
rep = self
# Create how_many copies increasing the date each time
how_many.times do
rep = rep.clone
if repeat_frequency == 'weekly'
rep.date += 1.week
elsif repeat_frequency == 'monthly'
rep.date += 1.month
else
raise "Unrecognized repeat frequency."
end
rep.save!
end
end
Then your controller code will be something like the following:
@service = Service.new(params[:service])
if @service.save
if !params[:weeks_number].blank?
repeats = params[:weeks_number].to_i
repeat_frequency = 'weekly'
elsif !params[:months_number].blank?
repeats = params[:months_number].to_i
repeat_frequency = 'monthly'
end
@service.create_repeats(repeats, repeat_frequency)
end
I know this doesn't defer all the logic to the model but some parameters really need specific logic to determine how they are translated from the view to the model layer.
You may also want to check that params[:weeks_number]
or params[:months_number]
are a valid number and that the user has not specified both.
I followed Shadwell's suggestion. While not moving all to the model, I ended up with reasonably clean views and controller:
View:
<%= radio_button_tag :repeat_type, :none %> No<br/>
<%= radio_button_tag :repeat_type, :week %> Every week for <%= text_field_tag :repeat_weeks %> weeks.<br/>
<%= radio_button_tag :repeat_type, :fixed_month %> Every month for <%= text_field_tag :repeat_fixed_months %> months. (Eg. Oct 2, Nov 2, etc.)<br/>
<%= radio_button_tag :repeat_type, :fluid_month %> Each month for <%= text_field_tag :repeat_fluid_months %> months. (Eg. last Sunday of March, last sunday of April, etc.)
Controller:
def create
@service = Service.new(params[:service])
if @service.save
frequency = params[:repeat_type]
how_many = params[("repeat" + frequency + "s").to_sym]
@service.create_repeats(how_many, frequency)
redirect_to @service, :notice => "Servizio creato."
else
render :action => :new
end
end
Model:
def create_repeats(how_many, frequency)
replica = self
how_many.times do
replica = replica.clone
case frequency
when "week" then
replica.date += 1.week
when "fixed_month" then
replica.date += 1.month
when "fluid_month" then
replica.date = replica.date.next_similar_date
else
return
end
replica.save!
end
end
精彩评论