基于Rails中的属性路由子目录

时间:2015-11-02 02:12:15

标签: ruby-on-rails

我正在构建博客,该博客使用文章模型来支持具有各自索引页面的两种不同的文章类型。我试图按照Hubspot使用单一模型进行管理的方式设置它(类型之间的唯一区别是目标受众,因此它是表单中的下拉列表)。

我希望网址别名可以路由到/foo/:article_id/bar/:article_id,具体取决于@article.type属性的值。

这是否可以使用rails路由和单个模型/控制器实现?

我试过了:

resources :articles, :path => "foo"
resources :articles, :path => "bar"

有效,但是:

  1. 我在查看动作中检查了网址和article.type,以确定它不是foobar,而不是/bar/:foo_article_idprivate RecyclerView mRecyclerViewCompletedTask; private RecyclerView.Adapter mAdapterCompletedTask; private RecyclerView.LayoutManager mLayoutManagerCompletedTask; private static String LOG_TAG = "RecyclerViewActivity"; private RecyclerView mRecyclerViewInCompleteTask; private RecyclerView.Adapter mAdapterInCompleteTask; private RecyclerView.LayoutManager mLayoutManagerInCompleteTask; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); mRecyclerViewCompletedTask = (RecyclerView) findViewById(R.id.my_recycler_view_completed_task); mRecyclerViewCompletedTask.setHasFixedSize(true); mLayoutManagerCompletedTask = new LinearLayoutManager(this); mRecyclerViewCompletedTask.setLayoutManager(mLayoutManagerCompletedTask); mAdapterCompletedTask = new MyRecyclerViewAdapterCompletedTask(getDataSet()); mRecyclerViewCompletedTask.setAdapter(mAdapterCompletedTask); LinearLayoutManager layoutManager1 = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false); mRecyclerViewCompletedTask.setLayoutManager(layoutManager1); mRecyclerViewInCompleteTask = (RecyclerView) findViewById(R.id.my_recycler_view_incomplete_task); mRecyclerViewInCompleteTask.setHasFixedSize(true); mLayoutManagerInCompleteTask = new LinearLayoutManager(this); mRecyclerViewInCompleteTask.setLayoutManager(mLayoutManagerInCompleteTask); mAdapterInCompleteTask = new MyRecyclerViewAdapterInCompleteTask(getDataSet()); mRecyclerViewInCompleteTask.setAdapter(mAdapterInCompleteTask); LinearLayoutManager layoutManager2 = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false); mRecyclerViewInCompleteTask.setLayoutManager(layoutManager2); } @Override protected void onResume() { super.onResume(); ((MyRecyclerViewAdapterCompletedTask) mAdapterCompletedTask).setOnItemClickListener(new MyRecyclerViewAdapterCompletedTask.MyClickListener() { @Override public void onItemClick(int position, View v) { Log.i(LOG_TAG, " Clicked on Item " + position); } }); ((MyRecyclerViewAdapterInCompleteTask) mAdapterInCompleteTask).setOnItemClickListener(new MyRecyclerViewAdapterInCompleteTask.MyClickListener() { @Override public void onItemClick(int position, View v) { Log.i(LOG_TAG, " Clicked on Item " + position); } }); } private ArrayList<DataObject> getDataSet() { ArrayList results = new ArrayList<DataObject>(); for (int index = 0; index < 20; index++) { DataObject obj = new DataObject("Some Primary Text " + index, "Secondary " + index); results.add(index, obj); } return results; } 看起来很理想

  2. 我不希望能够发布foo文章,并且可以通过转到curl -X PUT -H "Content-Type: application/json" -d '{"name":"Billy Bowler"}' -H "Authorization: BASIC <auth-token>" http://localhost/Bowling/public/api/leagues/1/bowlers 来查看它。这可以在这里完成。

  3. 它使用单个索引操作,这意味着视图格式化将包含一系列基于类型的条件,这些条件会让人感到骇客。

  4. 还有其他解决方案没有这些缺点吗?

2 个答案:

答案 0 :(得分:0)

有三个ActiveRecord模型而不是一个: ArticleFooArticleBarArticle

Article模型应包含两者共有的所有属性和代码,并且不应包含任何控制器或视图

FooArticle模型和BarArticle模型都应在Article关系中引用has_one并使用delegate关键字映射{Article的功能1}}更具体的版本。然后,您可以为Foo和Bar提供单独的控制器和视图,但在一个模型中具有所有功能和代码。

有可能让Foo和Bar都引用相同的文章,因此您可能需要注意这一点。

答案 1 :(得分:0)

首先,您所指的是Single Table Inheritance

#app/models/article.rb
class Article < ActiveRecord::Base
  # needs a "type" column
end

#app/models/foo.rb
class Foo < Article
end

#app/models/bar.rb
class Bar < Article
end

两者都将使用文章表(任何Google搜索者的参考!)。

有几个修复方法。

您遇到的主要问题是控制器

您试图确定要使用哪种控制器结构。如果您使用上述设置(赢得不必更改模型中的任何内容),您将能够明确区分这两个模型。唯一剩下的就是确定使用哪条路线。

为了简明扼要,我使用自己的模块查找ArticlePost,并将请求发送到控制器:

#config/routes.rb
%w(foo bar).each do |o|
   get "/#{o}/:id", to: Dispatcher.new(self), as: o.to_sym #-> url.com/foo/1 & url.com/bar/2
end

#lib/dispatcher.rb
class Dispatcher

  #http://blog.arkency.com/2014/01/short-urls-for-every-route-in-your-rails-app/
  ##########################################

  #Init
  def initialize(router)
    @router = router
  end

  #Env
  def call(env)
    id     = env["action_dispatch.request.path_parameters"][:id]
    model  = env["action_dispatch.request.path"].gsub("/", "") #-> /foo
    record = model.titleize.constantize.find id #-> looks up in the specific model (foo/bar)

    if record
      ArticlesController.action("show").call(env)
    else
      raise ActiveRecord::RecordNotFound
    end
  end

end

最后,您可以将以下内容传递给articles#show操作:

#app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
   def show
      model = request.path.gsub("/", "") #-> "foo"
      @article = model.titleize.constantize.find params[:id]
   end
end