Method for action in controller - ruby-on-rails

I have a controller which contains an action:
class VotesController < ApplicationController
def action_1
#user = User.find_by(uid: params[:uid])
#user.votes.pluck(:author_uid).delete(current_user.uid)
current_user.user_votes.pluck(:recipient_uid).delete(#user.uid)
redirect_to root_url
end
end
Which method should it have when I call it in view file:
= link_to 'Dislike', { controller: "votes", action: "action_1", uid: friend.uid }, method: "WHICH???"
Thanks!

Same method which we used in rails 3. i.e. 'GET'
In rails 4 only update action is change with method 'PATCH' and 'PUT' is also working.

You need to let the rails router know there is a controller action you can access. So you need to create the entry for it in your routes file to have access to it in the views.
Something like:
resources :votes do
get 'action_1', on: :collection
end
Or another type of action, depending on its purpose (see REST methods)
Then you can use action_1_votes_url(uid: friend.uid) or action_1_votes_path(uid: friend.uid) in your views

You have VotesController which is dedicated for Vote resource, and the purpose of action_1 is to delete from such resource. So there is no need to make a custom action name.
The best action name for this case is delete.
And then the link method would be delete as well.

Related

How to call a mailer action in a controller from a link_to post

I'm trying to call a mailer I have in the create action in my interests controller:
def create
if #interest.save
UserMailer.interest_to_seller(#interest).deliver_now
etc....
This works great when I'm going to the CRUD /interest/new form and creating it there, but I'm actually trying to call this from a post method in a different place. It's as if the create actions is being skipped all together, but that's impossible because the record is being created, right?
My routes.rb:
resources :seller_listings do
post :add_interest, on: :member
end
And in my view:
<%= link_to add_interest_seller_listings_path(m), method: :post do %>
Add Interest & Fire Email!
<%end%>
And in the interest controller, I have this action that that the post in the routes file calls:
def add_interest
current_user.mark_buyer_interest(seller_listing)
Which references this in the user.rb:
def mark_buyer_interest(listing)
buyer_interests.create(seller_listing: listing.id, accepted_by_seller: 0)
end
This works well, records are created, but the Mailer is skipped. Any suggestions? I've never done it this way before so any advice would be great. Thank you!
I think you should call UserMailer.interest_to_seller(#interest).deliver_now again in mark_buyer_interest.
def mark_buyer_interest(listing)
new_interest = buyer_interests.create(seller_listing: listing.id, accepted_by_seller: 0)
UserMailer.interest_to_seller(new_interest).deliver_now
end

Delete session variable with link_to

I'm wondering what's the best way to implement a link or a button that deletes a session object ( session[:object] ). I'm storing some data in the browser and users must be able to delete these whenever they want. Any idea ?
I would create a route called clear_[whatever], and bind it to a custom action in your controller.
your route would look like this:
get '/clear-[whatever]', to: '[your controller]#clear_[whatever]', via: [:destroy], as: :clear_[whatever]
your button would then be:
<%= link_to clear_[whatever]_path ... %>
and your controller action should do:
def clear_[whatever]
#clear = session[:whatever] = nil
if #clear ...
...
else
...
end
You could make a controller (or, alternatively, a non-REST method in your object's existing controller):
Controller
class WidgetSessionsController < ApplicationController
# "Delete" widget session data
def destroy
# Remove the widget from the session
#_current_user = session[:widget] = nil
end
end
routes.rb
# obviously you could add create and update here
resources :widget_sessions [only: destroy]
View
<%= link_to 'Click here to delete your widget session!', widget_session_path(), method: :delete %>

Why does the params "id" key change from params[:id] into params[:model_id]?

When I go to the characters controller, show action, all the normal params[:id] is as how it should be according to REST.
In the show view, I render a partial. In that partial, I have a link that goes to the vote_socionics action. This action is defined under a socionics_votes module, which gets included by the characters controller. (I have it set up this way because I have other controllers that also include this module).
My problem is that when I click on this link, and it goes to the set_votable private method within the socionics_votes_module.rb file, the params[:id] is no longer present. Using pry, I found that it actually turns into params[:character_id]
Questions:
1) Why does this happen (is it because it goes to a "different" controller, even if it's a module?)
2) How do I work around this? I would think that it would be more elegant to have it be params[:id], instead of having to do an if-else to account for both keys.
characters_controller.rb
class CharactersController < ApplicationController
include SocionicsVotesModule
def show
#character = Character.find(params[:id])
end
characters/show.html.haml
= render partial: 'votes/vote_socionics',
locals: { votable: #votable, votable_name: #votable_name, socionics: #socionics }
_vote_socionics.html.haml
= link_to content_tag(:div,"a"), send("#{votable_name}_vote_socionics_path", votable, vote_type: "#{s.type_two_im_raw}"),
id: "vote-#{s.type_two_im_raw}",
class: "#{current_user.voted_on?(votable) ? 'voted' : 'not-voted'}",
method: :post,
data: { id: "#{s.type_two_im_raw}" }
socionics_votes_module.rb
module SocionicsVotesController
extend ActiveSupport::Concern
included do
before_action :set_votable
end
private
def set_votable
votable_constant = controller_name.singularize.camelize.constantize
#votable = votable_constant.find(params[:id]) # This is where it fails, since there is no params[:id], and rather, params[:character_id]
end
def set_votable_name
#votable_name = controller_name.singularize.downcase
end
routes.rb
concern :socionics_votes do
post 'vote_socionics'
end
resources :characters, concerns: :socionics_votes
resources :celebrities, concerns: :socionics_votes
resources :users, concerns: :socionics_votes
The URL of the link in the partial when hovered over.
localhost..../characters/4-cc/vote_socionics?vote_type=neti
Something like .find(params[:id] || params[:"#{#votable_name}_id"]) didn't work, and seems silly.
You need to add the vote_socionics route as a member of the resource:
concern :socionics_votes do
member do
post 'vote_socionics'
end
end
This way the id parameter gets set correctly

ActiveAdmin action items depending on status of data

I want to hide the edit path if the object to edit has a certain status.
How can I do that?
I finally did it. I needed two things:
Redirect when access directly and hide buttons to the edit page.
To redirect when the user try to access directly to the edit page I use a before_filter:
before_filter :some_method, :only => [:edit, :update]
def some_method
redirect_to action: :show if status == something
end
To hide the buttons I do it like this:
ActiveAdmin.register Model do
config.clear_action_items!
action_item :only => [:show] , :if => proc { instance.status == something } do
link_to 'Edit', edit_model_path(instance)
end
end
If you are talking about hiding the edit link that is shown by default (along with the view and delete links) in the index action, you can customize the index view as follows:
ActiveAdmin.register Model do
index do
column :actions do |object|
raw( %(#{link_to "View", [:admin, object]}
#{link_to "Delete", [:admin, object], method: :delete}
#{(link_to"Edit", [:edit, :admin, object]) if object.status? }) )
end
end
end
Because the content of the column will be only what is returned by the column block, you need to return all three (or two) links at once as a string. Here raw is used so that the actual links will be displayed and not the html for the links.
This can be achieve using the following:
ActiveAdmin.register Object do
index do
column :name
actions defaults: true do |object|
link_to 'Archive', archive_admin_post_path(post) if object.status?
end
end
end
Note that using defaults: true will append your custom action to active admin default actions.
You could create a before_filter in your controller that only applies to edit action. It could check the status, and allow it to run or redirect_to depending on the return of the method.
Something like this in your applications controller:
def some_method
if foo.bar == true
redirect_to foos_path
end
end
Then in the beginning of your controller of question
before_filter :some_method, :only => :edit
A fully customizable solution would be to use an authorization adapter, either a custom one or a library such as pundit or cancan: https://activeadmin.info/13-authorization-adapter.html
My use case was around restricting actions based on the context (e.g. the user editing). I solved it locally like this:
controller do
def action_methods
if condition?
super
else
super - ['edit', 'update']
end
end
end
if u want to hide the "edit" link (in active_admin views) for object if the object holds some specific value, u can override the default view for the method and add condition before the link is displayed.

How to call a non action method by clicking a button in Rails

Forgive me if this is a very newby question.
how can i call a method (sharing an object on facebook) when user clicked on the share button in the view.
I can do the share/facebook parts, i just don't know how to call a method from the model when the user clicks on a button
my_controller.rb
def do_something
...
end
routes.rb
get "/something" => "my_controller#do_something", :as => :do_something
#you can also use post, put, delete or match instead of get
view
<%= link_to "call do something", do_something_path %>
for post etc...
<%= link_to "call do something", do_something_path, method: :post %>
I see two potential answers depending on your specific needs.
If you want to add a method to your model outside of the columns you've created for your object you can do so in the model.rb file:
model.rb
def name_twice
"#{self.name}#{self.name}"
end
You can then take an instance of a model to call this: "#model.name_twice".
If you want to add another routed method in the controller, you can define it in your models_controller file:
models_controller.rb
def approve
#model = Model.find_by_id(params[:model_id])
model.toggle!(:approved)
redirect_to #model
end
In order for the new controller function to work, you must add it in the routes file:
routes.rb
resources :models do
get 'approve', :on => :member
end
Hope this might be a little helpful. These examples should give you an idea of how to add other methods/actions to a model/controller.

Resources