【问题标题】:Dynamic CMS like routes in ruby on rails动态 CMS,例如 ruby​​ on rails 中的路由
【发布时间】:2010-10-21 01:09:35
【问题描述】:

我想创建一个类似于 CMS 的网站,用户从一些通用页面开始,即

  • 主页
  • 关于
  • 联系方式
  • 等

从那里可以动态添加子页面,例如

  • 主页
    • 文章
      • 第1条
        • 某事
          • 其他的东西
      • 第 2 条
  • 关于
  • 联系方式
  • 等

为了实现这一点,我计划使用某种自我引用关联,例如

class Page < ActiveRecord::Base
  belongs_to :parent, :class_name => 'Page'
  has_many :children, :class_name => 'Page'
end

我正在努力解决的一件事是路线生成。因为页面可以动态添加,所以我需要为这些页面动态生成路由,并且无法知道页面可以嵌套多少层

所以如果我从主页开始: /

然后开始添加页面,即

/articles/article1/something/something-else/another-thing

如何使用 Rails 路由模型实现类似的功能?

【问题讨论】:

    标签: ruby-on-rails


    【解决方案1】:

    一旦您有某种方法可以为您的Page 记录生成 URL 字符串(这部分由您决定),您就可以映射config/routes.rb 中的每个页面:

    Page.all.each do |page|
      map.connect page.url, :controller => 'pages', :action => 'show', :id => page
    end
    

    并让观察者挂钩页面模型以在发生变化时重新加载路由:

    class PageObserver < ActiveRecord::Observer
      def reload_routes(page)
        ActionController::Routing::Routes.reload!
      end
      alias_method :after_save,    :reload_routes
      alias_method :after_destroy, :reload_routes
    end
    

    别忘了编辑config/environment.rb 来加载观察者:

    # Activate observers that should always be running
    config.active_record.observers = :page_observer
    

    【讨论】:

    • 这是一个很好的解决方案,但你如何将它转换为 rails 3 'match' 命令?
    • 如果您使用的是 rails 3,请使用 MyApplication::Application.reload_routes! 重新加载您的路线
    • 我在使用这种方法时遇到的问题是,在运行时重新加载路由只适用于调用观察者方法的 ruby​​ 进程。如果您有多个 ruby​​ 进程(例如多个独角兽工人),即使他们知道数据库中的新记录,他们也不会选择新路线。结果是一些访问者将无法访问您的新页面,因为就处理请求的工作人员而言,路由将不存在。唯一的解决方案是重新启动整个应用程序。我想。
    • 作为上述的后续,如果您使用的是 unicorn,您可以将 ActionController::Routing::Routes.reload! 替换为 system("kill -USR2 `cat #{Rails.root}/tmp/pids/unicorn.pid`") 这将优雅地重新启动 Unicorn 服务器,以便所有工作人员都能选择新的路由。
    【解决方案2】:

    解决此问题的一种方法是从模型上的钩子中动态加载路由。例如,我网站上Slug 模型的 sn-p:

    class Slug < ActiveRecord::Base
    
      belongs_to :navigable
    
      validates_presence_of :name, :navigable_id
      validates_uniqueness_of :name
    
      after_save :update_route
    
      def add_route
        new_route = ActionController::Routing::Routes.builder.build(name, route_options)
        ActionController::Routing::Routes.routes.insert(0, new_route)
      end
    
      def remove_route
        ActionController::Routing::Routes.routes.reject! { |r| r.instance_variable_get(:@requirements)[:slug_id] == id }
      end
    
      def update_route
        remove_route
        add_route
      end
    
      def route_options
        @route_options ||= { :controller     => navigable.controller, 
                             :action         => navigable.action, 
                             :navigable_id   => navigable_id,
                             :slug_id        => id }
      end
    
    end
    

    这会在保存后以最高优先级(内存中的路由数组中的 0)插入路由。

    另外,听起来您应该使用树管理插件,并且喜欢很棒的嵌套集或更好的嵌套集来管理您网站的树。

    【讨论】:

      【解决方案3】:

      你必须自己解析路由

      map.connect '*url', :controller => 'pages', :action => 'show'
      

      现在您的操作中应该有一个params[:url] 可用,它是请求路径,作为一个由斜杠分隔的数组。一旦你有了这些字符串,从那里找到你需要的模型就很简单了。

      那是凭记忆,已经很久了。希望它对你有用。

      【讨论】:

        【解决方案4】:

        查看 RadiantCMS 资源,据我了解他们的自我描述,他们实现了该功能。

        【讨论】:

          【解决方案5】:

          我已经在 Rails gem 中实现了类似的功能,使用自引用关联和类似 js 接口的树来重新排序和嵌套“页面”。

          模板语言和身份验证/授权留给开发人员实施。 https://github.com/maca/tiny_cms

          【讨论】:

            猜你喜欢
            • 2014-11-08
            • 2013-10-09
            • 1970-01-01
            • 2015-05-15
            • 2011-04-17
            • 1970-01-01
            • 1970-01-01
            • 2011-01-05
            • 1970-01-01
            相关资源
            最近更新 更多