class Muck::ContentsController < ApplicationController include MuckContents::Models::MuckContentHandler uses_tiny_mce(:options => MuckContents.configuration.advanced_mce_options, :raw_options => MuckContents.configuration.raw_mce_options, :only => [:new, :create, :edit, :update]) before_filter :login_required, :only => [:create, :edit, :update, :destroy] before_filter :setup_parent, :only => [:new, :create] before_filter :get_secure_content, :only => [:edit, :update, :destroy] before_filter :setup_layouts, :only => [:new, :create, :edit, :update] def show handle_content_request end # If a content object is not found this method will render a 404 for users that are not allowed to add content. # If the user is allowed to add content a redirect to new is performed so that the content can be added. # # Notes: # Override 'new' by setting up @content and passing in a custom message via @new_content_message # For example: # def new # @content = Content.new(:custom_scope => 'my-stuff') # @new_content_message = 'Add Content to My Stuff' # super # end # # It is also simple to override the new template. Simply create a template in app/views/contents/new.html.erb # and add something similar to the following: #
# <%= output_errors(t('muck.contents.problem_adding_content'), {:class => 'help-box'}, @content) %> # <%= content_form(@content) do |f| -%> # <%# Add custom fields here. ie %> # <%= f.text_field :custom_thing %> # <% end -%> #
# # If you are overriding this method in a different controller (ie not contents_controller.rb) you can set # the template to render in a different location. For example, if you have a controller named blogs_controller.rb # that inherits Muck::ContentsController you can do this to render the new template in the /view/blogs/new.html.erb: # @new_template = 'blogs/new' # def new @content ||= Content.new @content.uri = params[:path] if params[:path] if logged_in? && has_permission_to_add_content(current_user, @parent, @content) flash[:notice] = @new_content_message || t('muck.contents.page_doesnt_exist_create') respond_to do |format| format.html { render :template => @new_template || 'contents/new'} format.pjs { render :template => @new_template || 'contents/new', :layout => 'popup'} end else # TODO think about caching this: @content = Content.find('404-page-not-found', :scope => MuckContents::GLOBAL_SCOPE) rescue nil if @content.blank? @content = Content.new(:title => I18n.t('muck.contents.default_404_title'), :body_raw => I18n.t('muck.contents.default_404_body'), :locale => I18n.locale.to_s) @content.uri = '/404-page-not-found' @content.save! end @title = @content.locale_title(I18n.locale) respond_to do |format| format.html { render :template => "contents/show", :status => 404 } format.all { render :nothing => true, :status => 404 } end end end def create @content = Content.new(params[:content]) @content.contentable = @parent if @parent @content.creator = current_user @content.current_editor = current_user @content.locale ||= I18n.locale return permission_denied unless has_permission_to_add_content(current_user, @parent, @content) @content.save! respond_to do |format| format.html do after_create_redirect end format.json do after_create_json end end rescue ActiveRecord::RecordInvalid => ex if @content @errors = @content.errors.full_messages.to_sentence else @errors = ex end message = t('muck.contents.create_error', :errors => @errors) respond_to do |format| format.html do flash[:error] = message render :template => 'contents/new' end format.json { render :json => { :success => false, :message => message, :errors => @errors } } end end # If you are overriding this method in a different controller (ie not contents_controller.rb) you can set # the template to render in a different location. For example, if you have a controller named blogs_controller.rb # that inherits Muck::ContentsController you can do this to render the new template in the /view/blogs/edit.html.erb: # @new_template = 'blogs/edit' # def edit @page_title = @content.locale_title(I18n.locale) @content.setup_uri_path # be sure to recover uri_path or scope will get messed up when the content is saved. respond_to do |format| format.html { render :template => @edit_template || 'contents/edit'} format.pjs { render :template => @edit_template || 'contents/edit', :layout => 'popup'} end end def update @content.current_editor = current_user @content.update_attributes!(params[:content]) respond_to do |format| format.html do after_update_redirect end format.json { render :json => { :success => true, :content => @content, :parent_id => @parent ? @parent.id : nil, :type => 'update' } } end rescue ActiveRecord::RecordInvalid => ex @errors = @content.errors.full_messages.to_sentence message = t('muck.contents.update_error', :errors => @errors) respond_to do |format| format.html do flash[:error] = message render :template => 'contents/edit' end format.json { render :json => { :success => false, :message => message, :errors => @errors } } end end def destroy @content.destroy respond_to do |format| format.html do flash[:notice] = t('muck.contents.content_removed') after_destroy_redirect end format.js do render(:update) do |page| page << "jQuery('##{@content.dom_id}').fadeOut();" end end format.json { render :json => { :success => true, :message => t("muck.contents.content_removed"), :content_id => @content.id } } end end protected def after_create_redirect redirect_to @content.uri end def after_create_json # HACK there should be a way to force polymorphic_url to use an id instead of to_param update_path = polymorphic_url([@parent, @content]).gsub(@content.to_param, "#{@content.id}") # force the id. The slugs can cause problems during edit render :json => { :success => true, :content => @content, :parent_id => @parent ? @parent.id : nil, :update_path => update_path, :preview_path => @content.uri, :type => 'create' } end def after_update_redirect redirect_to @content.uri end def after_destroy_redirect redirect_back_or_default(current_user) end # Setups up the layouts that are available in the 'layouts' pulldown. # Override this method to change the available layouts. Note that the # layout will need to exist in your 'views/layouts' directory def setup_layouts @content_layouts = [] get_layouts(File.join(::Rails.root.to_s, 'app', 'views', 'layouts')).each do |layout| @content_layouts << OpenStruct.new(:name => layout.titleize, :value => layout) end end def get_layouts(path) layouts = [] Dir.glob("#{path}/*").each do |layout_file| if File.directory?(layout_file) layouts << get_layouts(layout_file) else if layout_file.include?('.html.erb') || layout_file.include?('.html.haml') trimmed_layout_file = File.basename(File.basename(layout_file, '.*'), '.*') # get ride of html.erb, html.haml if trimmed_layout_file.first != '_'&& # don't include partials layouts << trimmed_layout_file end end end end layouts.flatten end # This method checks to see if the specified user has the right o # add content. Override this method in an individual controller # to provide more restrictive or more liberal permissions. # Parameters: # user - The user attempting to add content. # parent - The parent object of the content. May be nil. # content - The content to be added. In an overridden method may want to check scope on the content # to be sure a user doesn't attempt to change the scope to something they shouldn't have # permission to. def has_permission_to_add_content(user, parent, content) return true if user.can_add_root_content? return false if parent.blank? parent.can_add_content?(user) end # Pass the numeric id to this method to ensure that the operations update and delete occur on the correct object def get_secure_content @content = Content.find(params[:id]) if !@content.can_edit?(current_user) respond_to do |format| format.html do flash[:notice] = I18n.t('muck.contents.cant_delete_content') redirect_back_or_default current_user end format.js { render(:update){|page| page.alert I18n.t('muck.contents.cant_delete_content')}} end end end def setup_parent @parent = get_parent end end