I am trying to call a method of one controller from within a different view.
I saw the following post Rails call destroy method from within another controller, but I am doing something wrong with my implementation.
The method I am trying to call is in an accessor controller.
def remove_permission_from_index
Accessor.find(params[:id]).destroy
respond_to do |format|
format.html { redirect_to tasks_url }
format.json { head :no_content }
end
end
This controller also has the following strong param method
def accessor_params
params.require(:accessor).permit(:accessor_id, :access_rights, :task_id)
end
My view is calling the following code
<%= link_to 'Delete', {:controller => "accessors", :accessor => elem} ,method: :remove_permission_from_index, data: { confirm: "Are you sure?" }%> </p>
where elem an element within a set that is defined in the task controller
#canEdit = Accessor.select(:task_id).where("accessor_id = ? AND access_rights = ?", current_user, true)
#canEdit.each do |p|
p.task = Task.find(p.task_id)
When I am running my code I am getting the following error
param not found: accessor
def accessor_params
params.require(:accessor).permit(:accessor_id, :access_rights, :task_id)
end
end
and I can see that the accessor param is not being passed :
Parameters:
{"_method"=>"remove_permission_from_index"}
a) why is the accessor_params is being called if I am trying to access a different method
b) what am I doing wrong? After all I do set :accessor => elem
Could be a copy paste error but:
<%= link_to 'Delete', {:controller => "accessors", :accessor => elem} ,method: :remove_permission_from_index, data: { confirm: "Are you sure?" }%> </p>
should be more like:
<%= link_to 'Delete', {:controller => "accessors", :action => :remove_permission_from_index, :accessor => elem}, method: :delete, data: { confirm: "Are you sure?" }%> </p>
Related
Previously in Rails when using the button_to tag, it was possible to use a confirmation dialog like this
<%= button_to 'Destroy', #post, method: :delete, data: { confirm: 'Are you sure?' } %>
data: { confirm: 'Are you sure?' } is Rails magic data attribute that was used by #rails/ujs library under the hood
Following Rails 7, this library is no longer on by default. Instead of this Rails use Turbo library
And now this code does not work
There is no information in official Rails docs and Turbo handbook
What I tried
<%= button_to 'Destroy', #post, method: :delete, data: { turbo_confirm: 'Are you sure?' } %>
<%= button_to 'Destroy', #post, method: :delete, data: { 'turbo-confirm': 'Are you sure?' } %>
But there is no result
I didn't find any solution on SO but found on Hotwire forum. This solution with Stimulus action. I just improve it a little
<%= form_with model: #post, method: :delete, data: { controller: 'confirmation', message: 'Are you sure?', action: 'submit->confirmation#confirm' } do |f| %>
<%= f.submit 'Destroy' %>
<% end %>
// app/javascript/confirmation_controller.js
import { Controller } from '#hotwired/stimulus'
export default class extends Controller {
confirm(event) {
if (!(window.confirm(this.element.dataset.message))) {
event.preventDefault()
}
}
}
It works but it's quite difficult and looks ugly, and we are used to Rails being cool
In Rails with Turbo without rails-ujs to call confirmation popup window with button_to we need to use code like this
<%= button_to 'Destroy', #post, method: :delete, form: { data: { turbo_confirm: 'Are you sure?' } } %>
or
<%= button_to 'Destroy', #post, method: :delete, form: { data: { 'turbo-confirm': 'Are you sure?' } } %>
Both generate data-turbo-confirm attribute
So we need to add this attribute not to submit button (like in rails-ujs) but directly to form containing this button (let me remind you this tag generates a form with button)
This is a bit complicated in 7.0.3, if it is a page that is using turbo it looks like this:
<%= button_to "Delete",
user_path(user),
method: :delete,
class: "button tight danger",
form: {
data: {
turbo_confirm: "Are you sure you want delete?"
}
} %>
This makes a little form. Now if you are using turbo, but not on that specific page, you no longer get the simple comfirm: 'message' from the old rails ujs. Instead you have to use stimulus controllers.
# app/javascript/controllers/confirmation_controller.js
import { Controller } from "#hotwired/stimulus"
export default class extends Controller {
static values = { message: String };
confirm(event) {
if (!(window.confirm(this.messageValue))) {
event.preventDefault();
event.stopImmediatePropagation();
};
};
}
then
# app/javascript/controllers/index.js
import ConfirmationController from "./confirmation_controller"
application.register("confirmation", ConfirmationController)
then
<%= button_to "Delete",
user_path(user),
method: :delete,
class: "button danger",
form: {
data: {
turbo: false,
controller: "confirmation",
action: 'submit->confirmation#confirm',
confirmation_message_value: "Are you sure you want to delete?",
}
} %>
It is a bummer that rails removed functionality, but if you want to use hotwire you need to commit to full buy in to the whole ecosystem.
I'm not fully understanding this, but the following worked for me
<%= button_to post_path(post), method: :delete, form: { data: { turbo_confirm: 'Are you sure?' } } do %>
an svg which shows a trash can
<% end %>.
I also don't have anything that looks like the OP's confirmation_controller
not the original question, but as of rails 7.0.4, it would work the same (stimulus-free) :
<%= link_to("Del",
del_path,
data: { turbo_method: :delete, turbo_confirm: "Sure?" }) %>
I want to pass a parameter using link_to. (Also I am trying to use Bootstrap tab)
ilban.html.erb
<%= link_to '일반공지', '#home', { 'data-toggle' => 'tab', 'aria-controls'=>'home', 'role'=>'tab', :where => 1 } %>
cpu_controller.rb
#where = params[:where]
This code doesn't get where as an parameter. How can I fix it?
I have not tested it, but it should pass the params that you want.
link_to "Search", searches_path(:where => 1, :when => "Today"), { 'data-toggle' => 'tab', 'aria-controls'=>'home', 'role'=>'tab' }
Controller:
#where = params[:where]
In Rails 5, try this syntax for link_to
link_to 'Show', view_path(:id => view.id), { 'data-toggle' => 'tab', 'aria-controls'=>'home', 'role'=>'tab' }
In the place of view path you can edit with your controller path and pass the valid id that you need to link.
Or, try this syntax also to pass params
<%= link_to "Add car", {:controller => "car", :action => "add_car", :car => car.id }%>
And add in your controller
#car = Car.find(params[:car])
Rails 3.2
jQuery-Rails
I've searched all over and I've only found js ways to update a partial or add a partial via JS. I've had no luck with this one. Here is the issue:
I have a list of referrals on a page, the referrals are posted on the index page as partials. The referral box has a reply button and a count of how many replies per referral. Statically I had it working but I'm getting no luck with updating the referral box with the new count and replacing the reply button with an icon. The is getting to the database but I'm screwing something up with the refresh of the box. Help please!
Do I use locals to render the new variables?
Should I remove my if statements from the partial and just use the js.erb file to determine what to show?
Reply controller:
class RepliesController < ApplicationController
respond_to :html, :js
def new
#referral = Referral.find(params[:referral_id])
#reply = #referral.replies.new(:user_id => params[:user_id], :referral_id => params[:referral_id])
if #reply.save
format.html { notice: 'Replied' }
respond_with(#referral, :location => referrals_path)
end
end
end
_referral partial:
.referralBox.cornerShadow{:id => "Referral#{referral.id}"}
- if current_user == referral.user or current_user.role == 'administrator'
= link_to '<i class="icon-pencil icon-large icon-grey" rel="tooltip" title="Edit"></i>'.html_safe, edit_referral_path(referral), class: "referralEdit"
= link_to '<i class="icon-remove icon-large icon-grey" rel="tooltip" title="Delete"></i>'.html_safe, referral, method: :delete, data: { confirm: 'Are you sure?' }, class: "referralClose"
.referralProfile
= link_to "#{image_tag(referral.user.image.url, :class => "img-circle img-border border-white", :style => "thumb")}".html_safe, referral.user
%ul.unstyled.inline
%li
= referral.description
- unless referral.replies.count == 0
- if referral.user == current_user
%i.icon-comments.icon-large{"rel" => "tooltip", "title" => "Replies"}
= referral.replies.count
- else
%i.icon-comments.icon-large.orange{"rel" => "tooltip", "title" => "Replies"}
= referral.replies.count
- unless current_user == referral.user
- if referral.replies.any?
%i.icon-ok.icon-large.pull-right.orange{"rel" => "tooltip", "title" => "Replied"}
- else
= link_to '<i class="icon-ok icon-large pull-right icon-grey" rel="tooltip" title="Reply"> Reply</i>'.html_safe, new_referral_reply_path(:referral_id => referral.id, :user_id => current_user.id), :id => "ReplySubmit", :remote => true
new.js.erb view
$(".referralBox").html("<%= j(render(:partial => "#referral")) %>");
application.js
jQuery.ajaxSetup({
'beforeSend': function (xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
});
views/vehicles/_form.html.haml
= link_to "Deactivate", "/vehicles/deactivate"
I want to pass in #vehicle in my link_to above.
How do I do this?
controllers/vehicles_controller.rb
def deactivate
#vehicle = Vehicle.find(params[:id])
#vehicle.active = 0
#vehicle.save
respond_to do |format|
format.html { redirect_to vehicles_url }
format.json { head :no_content }
end
end
To make it easy and in Rails way, you can use Rails resources:
# routes.rb
resources :vehicles do
put 'deactivate', on: :member
end
# view:
= link_to 'Deactivate', deactivate_vehicle_path(#vehicle), method: :put
Best answer already given by Marek Lipka.
There is also a way using ajax
<%= link_to 'Deactivate', javascript::void(0), :class => "deactivate" %>
Put some script:
<script>
$(".deactivate").click(function() {
$.ajax({
type: "post",
url: "/vehicles/deactivate",
data: {id: <%= #vehicle.id %>},
dataType:'script',
beforeSend: function(){
// do whatever you want
},
success: function(response){
// do whatever you want
}
});
});
</script>
This worked for me, I ended up using the Update action in my controller.
= link_to "Deactivate", vehicle_path(#vehicle, :vehicle => {:active => 0}), method: :put, :class=>'btn btn-mini'
I've got a little demo setup in which clicking a checkbox toggles an attribute via AJAX. It's working fine, but Rails REALLY wants to render something, so I've basically resorted to creating a blank toggle.js.erb file in my views.
Controller action in question:
def toggle
#task = Task.find(params[:id])
respond_to do |format|
format.js do
if (#task.status != true)
#task.status = true
else
#task.status = false
end
#task.save
render :layout => false
end
end
end
View in question:
<h1>Tasks</h1>
<ul style="list-style-type: none;">
<% #tasks.each do |task| %>
<li id="<%= dom_id(task) %>">
<%= check_box_tag(dom_id(task), value = nil, checked = task.status) %>
<%= task.action %> <%= link_to 'Edit', edit_task_path(task) %>
<%= link_to 'Delete', task, :confirm => 'Are you sure?', :method => :delete, :remote => true %>
</li>
<% end %>
</ul>
<%= link_to 'New Task', new_task_path %>
<script>
$$('input').each(function(el) {
el.observe('click', function(event) {
// Get the task ID
var elId = el.id.split("_")[1];
// Build the toggle action path
var togglePath = '/tasks/' + elId + '/toggle/';
// Create request, disable checkbox, send request,
// enable checkbox on completion
new Ajax.Request(togglePath, {
onCreate: function() {
el.disable();
},
onSuccess: function(response) {
},
onComplete: function() {
el.enable();
}
});
});
});
</script>
Without the blank toggle.js.erb file I've got in the views, Rails still gives me an error saying that it's trying to render something.
Ultimately, I'd like to both not have to have a blank toggle.js.erb file, and I'd like to get that Prototype stuff into my static JavaScript stuff and out of the view.
I'm pretty new to Rails, so there's probably an easier way to be doing this, but I'm kind of stuck here.
render :layout => false means that you want to render 'toggle' view without layout.
If you don't want render anything at all, you should use :nothing => true option
def toggle
#task = Task.find(params[:id])
#task.toggle! :status
# if it used only by AJAX call, you don't rly need for 'respond_to'
render :nothing => true
end
EDIT: In Rails4/5 you can use head :ok instead of render nothing: true, it's more preferable way to do this, but result is the same.