In my Rails 5 app I've got a view in which I display information about users in a table.
#views/user_authorizations/pending.html.erb
<% if user_authorizations.any? %>
<table >
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
<% user_authorizations.each do |authorization| %>
<tr>
<td><%= authorization.registrant.full_name %></td>
<td><%= UserAuthorization.statuses[authorization.status].upcase %></td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<h5>No pending authorizations</h5>
<% end %>
One of the information is the account status:
<td><%= UserAuthorization.statuses[authorization.status].upcase %></td>
Which I would like to change to dropdown that allows the admin to change that status from pending to in review and save it right after the admin selects that status. How to achieve this if my view does not have a form_for tag?
Here is the controller responsible for that view
#user_authorizations_controller.rb
class UserAuthorizationsController < ApplicationController
def pending
authorize UserAuthorization
find_pending
end
private
def find_pending
@pending_user_authorizations = UserAuthorization.pending
end
end
CodePudding user response:
There are essentially a couple of ways to communicate from the browser to your rails application (and you want to do that, because the action of the administrator should change the state of your application).
One way is with a form. It does not need to be generated with form_for, you can use form_tag or just a plain HTML form tag (but in the latter case you will need to add all the CSRF extra fields yourself).
The other way is through javascript. You capture an event (in this case it would be a "change" event on your <select> tag. It does not need to be in a form for the event to be captured. Once you capture the event, you make an appropriate call (for instance with fetch, which is available in most browsers and also through polyfills) to the application.
From the receiving side, you will need to route a request to a corresponding action. For example
# in routes
resources :user_authorizations do
post :mark_in_review # will route /user_authorization/:id/mark_in_review
end
# controller
class UserAuthorizationsController
def mark_in_review
...
end
end
If you only want to allow changing from "pending" to "in review" (instead of both ways), you might just display a button instead of a select.
Youy might want to get the help of some small js framework like alpineJS or StimulusJS.
Something like:
import { Controller } from "stimulus"
class AuthorizationStatusChangeController extends Controller {
static values = {ident: Number}
markInReview() {
fetch(`/user_authorizations/${this.identValue}/mark_in_review`, {
credentials: "same-origin",
method: "POST"
})
}
}
<td data-controller="authorization-status-change"
data-authorization-status-change-ident-value="<%= authorization.id %>" >
<button data-action="change->authorization-status-change#markInReview">
Mark as "in review"
</button>
</td>
