Rails 5自定义资源prev/next方法放哪?MCQ标签筛选单题展示
Hey there! Let's tackle your two Rails questions with practical, convention-aligned solutions:
1. Should custom previous/next methods go in the controller or model in Rails 5?
Short answer: Stick them in the model.
Rails leans hard into the MVC pattern, where models own data and business logic, while controllers handle request routing, data coordination, and response rendering. Your previous/next behavior is about querying related records (finding the prior/next MCQ in a sequence) — this is core data logic that belongs in the model.
Putting these methods in the model also makes them reusable across different controllers or contexts, keeps your controllers lean and focused, and makes testing way easier (you can validate the logic independently of HTTP requests).
2. How to filter MCQs by tag and enable sequential viewing?
Since you're already using acts_as_taggable, you get a built-in tagged_with method to filter records by tag. We’ll combine that with custom model logic for sequential navigation, then wire everything up in the controller.
Step 1: Add sequential navigation methods to your model
First, add methods to the MultipleChoiceQuestion model to fetch the previous/next MCQ with the same tag. This keeps your controller clean and follows the "fat model, skinny controller" principle:
class MultipleChoiceQuestion < ApplicationRecord acts_as_taggable # Find the previous MCQ matching the specified tag def previous_in_tag(tag_name) self.class.tagged_with(tag_name) .where("id < ?", self.id) .order(id: :desc) .first end # Find the next MCQ matching the specified tag def next_in_tag(tag_name) self.class.tagged_with(tag_name) .where("id > ?", self.id) .order(id: :asc) .first end end
Step 2: Update your controller to handle tag filtering
Modify the show action in your MultipleChoiceQuestionsController to accept a tag parameter, fetch the current MCQ, and use the model methods to get navigation targets:
class MultipleChoiceQuestionsController < ApplicationController def show @mcq = MultipleChoiceQuestion.find(params[:id]) @current_tag = params[:tag] # Only load navigation links if a tag is provided if @current_tag.present? @previous_mcq = @mcq.previous_in_tag(@current_tag) @next_mcq = @mcq.next_in_tag(@current_tag) end end end
Step 3: Add navigation links in your view
In your show.html.erb (or equivalent view file), add links to let users navigate between tagged MCQs:
<div class="question-navigation"> <% if @previous_mcq %> <%= link_to "← Previous Question", mcq_path(@previous_mcq, tag: @current_tag) %> <% end %> <% if @next_mcq %> <%= link_to "Next Question →", mcq_path(@next_mcq, tag: @current_tag) %> <% end %> </div>
Quick notes:
- If you want to sort by something other than
id(likecreated_at), just adjust theorderclause in the model methods. - The
tagged_withmethod does exact matches by default. If you need fuzzy matching (MCQs with any matching tag), usetagged_with(tag_name, any: true). - For a better user flow, add an index action that lists all MCQs for a specific tag, linking directly to the first question in the sequence.
内容的提问来源于stack exchange,提问作者mazing

