How to Route Controllers Without Crud Actions

How to route controllers without CRUD actions?

You can specify actions you want to route like this:

resources :tests, except: [:new, :create, :edit, :update, :destroy] do 
collection do
get 'find'
get 'break'
get 'turn'
end
end

Should I use resource routing even for non-CRUD routes (Rails)?

I wouldn't use the resource(s) helpers. The name tells you it's used for resources and oauth logic are not resources.

You could refactor the routes a little bit though

namespace :oauth do
match :callback, via: [:get, :post]
get ":provider", action: :oauth, as: :at_provider
end

This creates this routes:

              oauth_callback GET|POST /oauth/callback(.:format)                                                                oauth#callback
oauth_at_provider GET /oauth/:provider(.:format) oauth#oauth

They are basically the same routes, DRYer and without misleading "resource" wording.

*Note the little change from "auth_at_provider" to "oauth_at_provider" introduced by the namespace

Excluding CRUD resources when only setting up member routes

The :only option tells Rails to create only the specified routes. Now if you pass empty array to the only option, it will not create any because it is expecting the action names in the array.

So this will work

resources :dishes, only: [] do

Reference: http://guides.rubyonrails.org/v3.2.9/routing.html ( 4.6 Restricting the Routes Created)

Non-CRUD Controller Actions

It sounds like you are talking about RESTful ideas (having actions called index, create, new, edit, update, destroy, show).

In MVC you can call an action largely whatever you want (so yes, you can call it uploadcsv if you want). If you want it fit RESTful principles you might want to think about what the action is doing (for example is a data upload essentially a create or an update function) and name it using one of the RESTful action names.

Rails CRUD route and controller method best practices

The simple explanation is:

because that's how God and DHH intended it.

The Rails CRUD conventions are quite pragmatic and allow you to avoid many pitfalls related to browser caching and security.

Lets take one example:

# config/routes.rb
resources :users, only: [:new, :create]

# app/controllers/users_controller.rb
class UsersController < ApplicationController
def new
@user = User.new
end

def create
@user = User.new(user_params)

if @user.save
sign_in(@user)
redirect_to root_path
else
render :new
end
end

private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end

Here we two separate routes GET /users/new and POST /users.

The first route is idempotent - it should look the same for any visitor and can be cached. The second is not - it should show the result of creating or attempting to create a resource.

When a user visits /users/new we POST the form to a different URI. That avoids history issues in the client.

We also render the form in the same request cycle if the input is invalid. This avoids the security issues that would arise if we tried to pass the form data back in redirect to /users/new and lets us return the semantically correct response code instead of a redirect.

It also ensures that our application is stateless in the restful sense since the previous action does not influence what we see if we were to visit /users/new.

On an architecture level, it allows you to leverage convention over configuration. You can just do:

def new
@user = User.new
end

And it will render views/users/new.html.erb because Rails can derive that the new action should render the new template. Having each controller action perform one single task is far better from a design and testing standpoint as it eliminates the need to test two separate code paths in the same method.

Rails routing: resources with only custom actions

If you are using scope, you should add a controller looks like

scope :notifications, :controller => 'notifications' do
post 'clear'
end

Or just use namespace

namespace :notifications do
post 'clear'
end

Link to some action of a different CRUD controller

Following @Ruban's comment, and as the docs mention, we can generate a URL for the desired action using the AdminUrlGenerator class as follow:

class FirstEntityCrudController extends AbstractCrudController
{
private $adminUrlGenerator;

public function __construct(AdminUrlGenerator $adminUrlGenerator)
{
$this->adminUrlGenerator = $adminUrlGenerator;
}
...
public function configureActions(Actions $actions): Actions
{
//The magic happens here
$url = $this->adminUrlGenerator
->setController(SecondEntityCrudController::class)
->setAction(Action::NEW)
->generateUrl();

return $actions
...
->add(Crud::PAGE_INDEX, Action::new('add-second-entity', 'Add second entity')
->linkToUrl($url)
);
}
}

This worked for me.



Related Topics



Leave a reply



Submit