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 %>
Related
I'm new to rails, and I've already learnt how to do CRUD using scaffold and using resource, I wanna know how to Do CRUD without using resource, However what I want to do is create custom methods for CRUD in the controller that will be like the traditional CRUD model. Please help me with this.
Actually, for the action index / new / show / create / edit / update / destroy, this is a convention in Ruby On Rails
If I'm right and if you're trying to change their name using resources in routes.rb (Changing by exemple the new action into def my_restaurant), Rails will render
Unknown action The action 'new' could not be found for
RestaurantsController
Netherless, you can create some methods to perform some particular action into the index, and add them in the "private section" you want to hide them to the public. There is no routes attach to this method.
class RestaurantsController < ApplicationController
def index
#restautants = Restaurant.all
#restaurants.sort_by_name
end
private
def sort_by_name
#some action here
end
end
If you want to create your own name method, you can personnalise it but you can't use resources "shortcut" in the routes.rb
by exemple :
#reviews_controller.rb
class ReviewsController < AplicationController
def index
#reviews = Reviews.all
end
def update
#review = Review.find(review_params[:id])
end
def history
#some action
end
private
def review_params
params.require(:review).permit(:liked, :comment, :id)
end
end
Then add a view
#app/views/reviews/history.html.erb
Don't forget the routes :
Rails.application.routes.draw do
resources :reviews, only: [:index, :update] do
collection do
get :history
end
end
end
I hope this will help you and complete the previous answer.
as for your second question :
I still do have one doubt tho..... Will <%= form_for #post do |f| %>
this form be enough for new_post and edit_post, will it automatically
identify them? If that's not enough can you please tell me the what
comes at new_post.html.erb and edit_post.html.erb....Thanks again for
the help.
If the form is the same for your new_post and edit_post, i may suggest you to put into a partial file. (For this example I used simple_form gem)
#app/views/posts/_form.html.erb
<%= simple_form_for(#post) do |f| %>
<%= f.input :name, label: "post name" %>
<%= f.input :photo, as: :file %>
<%= f.submit "Save", class:"btn btn-small btn-success" %>
<% end %>
and then render the partial in your views new file.
#app/views/posts/new.html.erb
<div>
<h1>New Post</h1>
</div>
<%= render "form" %>
Well I hope I could help you with this answer.
Do not hesitate too to read ruby documention. You may find more information that you're looking for too.
My answer may be redundant but it's the better way for me to clearly explain it...
In oder to use your own custom methods you need to create them in your controller, setup the route and if needed create an view.
# PostsController
def create_post
# Do your create stuff here
end
def read_post
# Do your read stuff here
end
def update_post
# Do your update stuff here
end
def delete_post
# Do your delete stuff here
end
# routes
post '/create_post', to: 'posts#create_post'
get '/read_post/:id', to: 'posts#read_post'
put '/update_post/:id', to: 'posts#update_post'
delete 'delete_post/:id', to: 'posts#delete_post'
With the controller and routes setup you will only need a view for the read_post method. The best way to do that is create the file: views/posts/read_post.html.erb
There is 7 CRUD routes to Create, Read, Update and Delete.
Rails.application.routes.draw do
get "restaurants", to: "restaurants#index"
get "restaurants/new", to: "restaurants#new", as: :new_restaurant
post "restaurants", to: "restaurants#create"
# NB: The `show` route needs to be *after* `new` route.
get "restaurants/:id", to: "restaurants#show", as: :restaurant
get "restaurants/:id/edit", to: "restaurants#edit", as: :edit_restaurant
patch "restaurants/:id", to: "restaurants#update"
delete "restaurants/:id", to: "restaurants#destroy"
end
So once the route create, you can create in the controller, the action that you need
class RestaurantsController < ApplicationController
def index
#restaurants = Restaurant.all
end
end
and the view
app/views/restaurants/index.html.erb.
The best practice is to create only the routes that you will need and to work in silos.
1 route, 1 controller action, 1 view.
I am working with rails I have a controller name books and has a user defined method in it .I need to call this method so that i can see the output on console.And I dont want to call this method in helpers.
def approve
#user=current_user.users.find params[:id]
puts '#{#usery}'
end
Also I Have a link
<%= link_to 'approve',users_path,data: { :confirm => 'Are you sure to delete the folder and all of its contents?'} %>
.When i click on this link I want to call the above method on it .
You'll just need to define a route and call it through that:
#config/routes.rb
resources :users do
get :approve, on: :member
end
<%= link_to "Approve", users_approve_path(#user) %>
As #Rich suggested that, you can achieve it by member. Please note that when you'll create a member route in member block
resources :users do
member do
get 'approve'
end
end
then you'll get the params[:id]. Like
def approve
#user = User.find params[:id]
puts '#{#user}'
end
and when create a member route using :on then you'll get params[:user_id]. Like
def approve
#user = User.find params[:user_id]
puts '#{#user}'
end
Path will be same in both cases that is
<%= link_to "Approve", users_approve_path(#user) %>
Source Rails - Adding More RESTful Actions
Happy coding !!!
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.
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.
Route
resources :cars do
collection do
get :f01a
end
end
Controller
class CarsController < ApplicationController
def f01a
#user = User.find(params[:id])
#count = Count.find_by_user_id(#user)
#count.increment!(:f02)
redirect_to #user
end
end
View
<%= button_to "add f01", f01a_cars_path %>
I can't get this to work. I need to execute this code from a button.
button_to sends a POST request, but your routing is setup to only accept GET requests. You should change it to:
resources :cars do
collection do
post :f01a
end
end
Since you're using params[:id] in your action, but not sending it in at all, you'll need to pass it in your button_to:
<%= button_to "add f01", f01a_cars_path(:id => something)
(Replace something with whatever ID you want to pass.)