Software Development |
Ruby on Rails
altered_beast Monitorship
The altered_beast data model shows that Users to Monitor a Topic via a Monitorship. What wasn't clear to me is what that actually meant for the User. I suspect Monitorship is a work in progress for the altered_beast authors.
Data Model
OK, first port of call is the schema. Looks a pretty standard many-to-many link table. The only interesting field is active.
db/schema.rb
create_table "monitorships", :force => true do |t| t.integer "user_id" t.integer "topic_id" t.datetime "created_at" t.datetime "updated_at" t.boolean "active", :default => true end
The User and Topic models confirm the many-to-many relationship. Once again the only twist is active, this time in the condition :conditions => {"#{Monitorship.table_name}.active" => true. In other words inactive Monitorships don't count.
app/models/topic.rb
has_many :monitorships, :dependent => :delete_all
has_many :monitoring_users, :through => :monitorships,
:source => :user, :conditions => {"#{Monitorship.table_name}.active" => true}
app/models/user.rb
has_many :monitorships, :dependent => :delete_all
has_many :monitored_topics, :through => :monitorships,
:source => :topic, :conditions => {"#{Monitorship.table_name}.active" => true}
active
In fact active is just a soft delete mechanism. The controller sets active to false instead of deleting the record.
app/controllers/monitorships_controller.rb (snippet)
def destroy
Monitorship.update_all ['active = ?', false], ['user_id = ? and topic_id = ?', current_user.id, params[:topic_id]]
respond_to do |format|
format.html { redirect_to topic_path(params[:forum_id], params[:topic_id]) }
format.js
end
end
The model ensures that any existing inactive record is used rather than creating a new one.
app/models/monitorship.rb (snippet)
before_create :check_for_inactive
def check_for_inactive
monitorship = self.class.find_by_user_id_and_topic_id_and_active(user_id, topic_id, false)
if monitorship
monitorship.active = true
monitorship.save
false
end
end
What is not clear to me is why Monitorship needs a soft delete. Normally you'd soft delete something if you want to retain reference integrity. But that doesn't seem to be a factor here.
Start/Stop monitoring
Users can start/stop monitoring a Topic on the Show view for the Topic. Checking the box launches an Ajax call to create the Monitorship; unchecking deletes the Monitorship via Ajax.
app/views/topics/show.html.erb (snippet)
<% @monitoring = logged_in? && !Monitorship.count(:id,
:conditions => ['user_id = ? and topic_id = ? and active = ?', current_user.id, @topic.id, true]).zero? %>
<% if logged_in? %>
<% form_tag monitorship_path(@forum, @topic), :style => 'margin-top:0em; float:right;' do -%>
<div>
<input id="monitor_checkbox" type="checkbox" <%= "checked='checked'" if @monitoring %>
onclick="if (this.checked) {<%= remote_function :url => monitorship_path(@forum, @topic) %>} else
{<%= remote_function :url => monitorship_path(@forum, @topic), :method => :delete %>}" />
<label id="monitor_label" for="monitor_checkbox">
<%= @monitoring ? I18n.t('txt.monitoring_topic',
:default => 'Monitoring topic') : I18n.t('txt.monitor_topic', :default => 'Monitor topic') %></label>
<%= hidden_field_tag '_method', 'delete' if @monitoring %>
<%= submit_tag :Set, :id => 'monitor_submit' %>
</div>
<% end -%>
<% end -%>
Actually there is a bug here. Perhaps two. The Ajax doesn't seem to work and the "Set" button explodes.
Sweeper
There is also a sweeper class to clean up Monitorships.
app/models/monitorships_sweeper.rb (snippet)
class MonitorshipsSweeper < ActionController::Caching::Sweeper
observe Monitorship
def after_save(monitorship)
FileUtils.rm_rf File.join(RAILS_ROOT, 'public', 'users', monitorship.user_id.to_s)
end
alias_method :after_destroy, :after_save
end
TODO
- Investigate sweepers.
But so what?
All of the above is understandable ... the only problem is that that is it. As far as I can tell Monitorships don't actually do anything. I suspect they are a work in progress by the authors.
