我正在构建博客,该博客使用文章模型来支持具有各自索引页面的两种不同的文章类型。我试图按照Hubspot使用单一模型进行管理的方式设置它(类型之间的唯一区别是目标受众,因此它是表单中的下拉列表)。
我希望网址别名可以路由到/foo/:article_id
或/bar/:article_id
,具体取决于@article.type
属性的值。
这是否可以使用rails路由和单个模型/控制器实现?
我试过了:
resources :articles, :path => "foo"
resources :articles, :path => "bar"
有效,但是:
我在查看动作中检查了网址和article.type
,以确定它不是foo
或bar
,而不是/bar/:foo_article_id
或private 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;
}
看起来很理想
我不希望能够发布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
来查看它。这可以在这里完成。
它使用单个索引操作,这意味着视图格式化将包含一系列基于类型的条件,这些条件会让人感到骇客。
还有其他解决方案没有这些缺点吗?
答案 0 :(得分:0)
有三个ActiveRecord模型而不是一个:
Article
,FooArticle
和BarArticle
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搜索者的参考!)。
有几个修复方法。
您遇到的主要问题是控制器。
您试图确定要使用哪种控制器结构。如果您使用上述设置(您赢得不必更改模型中的任何内容),您将能够明确区分这两个模型。唯一剩下的就是确定使用哪条路线。
为了简明扼要,我使用自己的模块查找Article
或Post
,并将请求发送到单控制器:
#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