基于Sinatra框架的映射方法存储位置咨询:控制器还是装饰器?
Great question—this is exactly the kind of design call that keeps our code clean and maintainable as Sinatra apps scale. Let’s break this down based on what the mapping is used for, and which approach fits best:
Go with a Decorator (Preferred for Presentation Logic)
If your only goal is to convert the region code to a human-readable name for display in views (e.g., showing "Île-de-France" instead of "75" to end users), this falls squarely into presentation layer logic—and decorators are perfect for this job.
Decorators let you wrap your model objects with view-specific formatting logic without cluttering the model or controller. For example, if you’re using a library like draper (a common decorator gem for Ruby apps), your decorator might look like this:
class RegionDecorator < Draper::Decorator delegate_all def region_name FranceRegionMapper.name_for(object.region_code) || "Unknown Region" end end # Separate module to hold the actual mapping (keeps decorator clean!) module FranceRegionMapper REGION_MAP = { "01" => "Ain", "75" => "Île-de-France", # Add all other French region codes here }.freeze def self.name_for(code) REGION_MAP[code] end end
In your controller, you’d pass the decorated model to the view:
get "/regions/:id" do @region = Region.find(params[:id]) @region = RegionDecorator.new(@region) erb :region_show end
Then in your view (region_show.erb), you just call <%= @region.region_name %>—no messy conversion logic cluttering your controller or view.
When Might a Controller Make Sense?
Only consider putting this logic in a controller if:
- You’re working on a tiny, single-purpose Sinatra app where adding a decorator gem feels overkill.
- The conversion is part of business logic (e.g., you need to filter or process data based on the region name before saving or returning it via an API).
Even then, don’t hardcode the mapping directly in your controller action! Extract it into a helper method or a separate module (like the FranceRegionMapper above) to keep your controller actions focused on handling requests and responses.
A Middle Ground: Reusable Service/Module
No matter which approach you pick, I strongly recommend keeping the actual region code-to-name mapping in a standalone module or class. This way:
- You can reuse the mapping anywhere in your app (controllers, decorators, models, etc.) without duplicating code.
- If the French region codes ever change (unlikely, but possible), you only need to update one file.
Final Takeaway
9 times out of 10, a decorator (paired with a reusable mapping module) is the right choice here. It keeps your code organized, follows the single-responsibility principle, and keeps your controllers lean—something that’s especially helpful as your Sinatra app grows.
内容的提问来源于stack exchange,提问作者user1913545

