lucky
lucky copied to clipboard
Unable to add file extension on routes that end with a path variable
Defining an action like this one fails to compile when the route ends in a variable and have a file extension:
class SomeAction < Lucky::Action
get "/reports/:report_name.csv" do
text "test"
end
end
Syntax error in expanded macro: add_route:27: expecting token ')', not '.'
report_name.csv,
^
Ok, it seems my PR fix works ok for standard routing purposes, but it breaks all of the path helpers and such. This becomes a bit trickier, and I would rather not monkey patch this. So, I'm proposing a new feature. The concept of a format.
Here's my thoughts.
You generate a new app, and in the config/ directory, there's a file that allows you to config your default format. If you generated a web app, it would be ".html", if you generated an API app, it would be ".json".
What this does is when you define a route like get "/home", it would actually store in the router as "get", "/home.html". If you decided to define the route as get "/home.html", it would see there's an extension on that, and store as "get","/home.html".
When you make a request through your browser with mysite.com/home, we would see the request come in, check against some headers for the mime type to see it should be ".html", then we append that and do the lookup for "/home.html". If you request in your browser mysite.com/home.html, then no need to append it because we already know. So we do
- check for file extension
- check against accept header
- check against content-type (maybe flip those 2?)
- maybe one last minute check before just 404
Sometimes you may need to have multiple actions that use different formats. You can't just throw .html at the end of every route and be ok. In this case, you would configure at the Action level. You could put this setting on ApiAction so all of your api routes use .json as their default, and all the web ones use .html as their default. Then you could say Reports::Index is default .csv even though it's on the web side. Of course, you could still just add the format to the end of the route get "/reports.csv", and that would work as well.
The idea here being that EVERY route stored in the LuckyRouter would have an extension on them. Then along with the methods like payload, and params, we also have extension which would tell us that route's extension.
Here's the even better part. By doing this, it would allow us to do this:
class Reports::CSV < BrowserAction
default_extension "csv" # whatever this becomes... I don't know
get "/reports/:report_name" do
# renders /reports/money.csv
end
end
class Reports::XML < BrowserAction
config_method_name "xml"
get "/reports/:report_name" do
# renders /reports/money.xml
end
end
class Reports::Show < BrowserAction
get "/reports/:report_name" do
# renders /reports/money.html
end
end
# then helpers become
Reports::CSV.path("money", format: "csv") #=> /reports/money.csv
Reports::Show.path("money") #=> /reports/money (assumed to be .html)
That suggestion makes things a lot more complicated. A new solution may be to use some middleware magic. I'm gonna roll with that in my app and see how it goes before submitting a new PR.
This is awesome. I know Rails has something similar. I was going to suggest this if it wasn't already planned.