Delete an attachement (an avatar) with Devise - ruby-on-rails

In my registrations/edit.html.erb view file I'd like to add a link to delete a current avatar (if it's attached). I've ended up with something like this:
<% if current_user.avatar.attached? %>
<%= link_to "Remove avatar", { action: :remove_avatar }, method: :put %>
<% end %>
In custom registrations_controller (inherited from Devise::RegistrationsController) I defined a method :remove_avatar:
def remove_avatar
self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
resource.avatar.purge_later
end
But I've got this error, which is probably caused by a lack of routes settings.
No route matches {:action=>"remove_avatar", :controller=>"registrations", :locale=>:ru}
What can I do to be able to link_to this method? Thank you.

Probably you would need something like this
put "remove_avatar", to: "registrations#remove_avatar"
in your routes.rb file.
Maybe it can get messier than this because of your directory structure, but it should work

Related

Custom controller route to update column active to false

I am trying to link to a custom controller route action and I'm doing something wrong. I have a Document model that handles uploading documents to my CRUD app. I want users to be able to 'delete' something, but not actually delete it from the system, but rather update the column 'active' to false. Then if someone with admin privileges can go ahead an complete the deletion. This process is needed because the app gets audited and we do not want to accidentally delete uploaded files.
I can't get the custom update action (remove) to work. When I rake routes I see:
remove_documents PUT /documents/remove(.:format) document#remove
In my routes file (I'll a couple similar routes I'll want to add later so I used collection it up this way):
resources :documents do
collection do
put "remove", to: "document#remove", as: :remove
end
end
In the Documents index view:
<%= link_to remove_documents_url(document), :method => :put do %>
<span class="fa fa-trash text-danger"></span>
<% end %>
My Controller:
def remove
#document = Document.find(params[:id])
#document.active = false
#document.save
html { redirect_to(:back, :notice => 'Document was successfully removed.')}
end
The link works, but then I get the following error:
NameError at /documents/remove.75 uninitialized constant DocumentController
raise unless e.missing_name? qualified_name_for(parent, const_name)
end
end
name_error = NameError.new("uninitialized constant #{qualified_name}", const_name)
name_error.set_backtrace(caller.reject {|l| l.starts_with? __FILE__ })
raise name_error
end
# Remove the constants that have been autoloaded, and those that have been
# marked for unloading. Before each constant is removed a callback is sent
If you want the remove action on a specific Document, change the routes to :
resources :documents do
member do
put "remove", to: "documents#remove", as: :remove
end
end
which gives you : remove_document PUT /documents/:id/remove(.:format)
and use it like :
<%= link_to remove_document_path(document), :method => :put do %>
<span class="fa fa-trash text-danger"></span>
<% end %>

Search box to find user in rails

I'm somewhat new to rails. I'm going through making the classic twitter clone right now. I want to have a search bar on my homepage that allows the user to search for a twitter handle, and if the handle exists, it will send the user to the show page for that twitter handle.
I've been following a RailsCast on how to implement a simple search, but instead of doing it on the index like the video, I want to do it on the show action. I've run into some problems though. The form sits on my user index view.
Here is the error:
ActionController::UrlGenerationError in Users#index
Showing c:/Sites/Projects/twitterapp/twitter/app/views/users/index.html.erb where line #2 raised:
No route matches {:action=>"show", :controller=>"users"} missing required keys: [:id]
Here is the form:
<%= form_tag(user_path, method: 'get') do %>
<%= text_field_tag(:search, params[:search]) %>
<%= submit_tag("Search", name: nil) %>
<% end %>
Here is my show action:
def show
#user = User.search(params[:search])
end
And here is my search method in my user model:
def self.search(search)
if search
find(:all, conditions:['name LIKE ?', "%#{search}%"])
else
find(:all)
end
end
Actually you cannot use the show method as a search result finder. Because according to the rails convention:
For any resource like users, rails scaffold generates index,new, show, create, update, delete methods based on your routes files.
Thus based on the conventional way, show method always asks for an object. Lets say you are using UserContoller show method. It asks for a user object. Which you haven't provide in the form. that's why :id missing error is given.
I would tell you to do some more learning. And for searching create a different method in a different controller and define that controller method to the routes.rb file. This is the best way to do.
If you still want to use the show method, then change the show methods routing from the routes.rb file. You've to manually declare the show action on routes file.
you are using user_path and path need to inform id from present user
you can do this in action :index but I recommend you to create a action to this
view
<%= form_tag(search_users_path, method: 'get') do %>
<%= text_field_tag(:search, params[:search]) %>
<%= submit_tag("Search", name: nil) %>
<% end %>
routes.rb
resources :users do
post 'search', :on => :collection
end
users_controller.rb
def search
#user = User.search(params[:search])
end
You should to create a view search.html.erb similar as index.html.erb
As Emu and Breno pointed what causing the problem user_path requires an user id
Solution idea:
Why not just point to users index action? like this:
<%= form_tag(users_path, method: 'get') do %>
<%= text_field_tag(:search, params[:search]) %>
<%= submit_tag("Search", name: nil) %>
<% end %>
users_controller.rb:
def index
if params[:search]
#user = User.search(params[:search])
end
end
and you can use ajax remote: true to handle the returned user object
Found your question via Google, but the responses and suggestions didn't work for me. Found another solution that did, so seems worth posting here.
"Search and Filter Rails Models Without Bloating Your Controller":
http://www.justinweiss.com/articles/search-and-filter-rails-models-without-bloating-your-controller/

How to include an image as link for datagrid gem?

I'm trying to implement the datagrid gem in Rails 4 but am not sure how to include a link in the Grid class.
I currently have for the UsersGrid class:
class UsersGrid
include Datagrid
scope do
User.order("users.created_at desc")
end
column(:avatar) do |user|
if user.avatar?
link_to ActionController::Base.helpers.image_tag(user.avatar.url, alt: "Profile"), user_path(user)
else
link_to ActionController::Base.helpers.image_tag("profile.gif", alt: "Profile"), user_path(user)
end
end
end
This generates the following error message referring to the link_to line :
undefined method 'user_path' for #<ActionView::Base:0x007f821d3115b8>
How should I adjust the code to make the link work?
Additional information:
View page:
<%= datagrid_form_for #grid, :method => :get, :url => users_path %>
<%= will_paginate(#grid.assets) %>
<%= datagrid_table(#grid) %>
<%= will_paginate(#grid.assets) %>
Controller method:
def index
#grid = UsersGrid.new(params[:users_grid]) do |scope|
scope.where(admin: false).page(params[:page]).per_page(30)
end
#grid.assets
end
I found the solution: I had to add :html => true to column(:avatar, :html => true). This way html code such as link_to work and I also no longer needed ActionController::Base.helpers to get access to the image_tage method.
It sounds like you don't have a route configured for a user resource in routes.rb.
To verify and see what path helpers are available, go to command line, navigate to the project directory, and type in rake routes. If properly configured you should see something like:
user GET /users/:id/(.:format) users#show
On the far left of the example above is the "Name" which is used to generate the path helper. So in the example above the name is "user" and Rails will automatically generate the helper user_path which accepts an argument that is a user's id. So user_path(1) is a helper for /users/1. If you pass in a User object (like you were in your example) it will just get the id from the User in the background e.g.) user_path(current_user) will find the id of current_user and return /users/1.
Read more about rake routes here.
Anyways, if user is missing from your routes.rb file you could add something like this to routes.rb:
get '/users/:id', :to => 'users#show', :as => :user
Keep in mind you likely already have something for the users resource, so you might be able to make an easier/cleaner change depending on how you have configured the file.

Delete action and destroy method

I have something like this in view:
<% if actions.include? "delete" %>
<%= link_to 'UsuĊ„', asset_path(asset), :method => :delete, :data => { :confirm => "Want to delete it?" }, :role => "link" %>
<% end %>
and this in assetcontroller:
def destroy
#asset = current_user.assets.find(params[:id])
#asset.destroy
redirect_to assets_path
end
the question is, why it "use" destroy method when action in view is "delete" ?
delete is method of HTTP protocol. destroy is the action of your controller.
Route with delete HTTP method leads to destroy action.
To edit this routes and make delete HTTP method lead to delete action (for example), you should edit config/routes.rb file.
This is because in your routes.rb file you have defined the model as a resource (or a generator like scaffold did). This means that the default CRUD routes are generated. If you want to do it another way, use your own routes instead of generating them.
http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions

Rails: "new or edit" path helper?

Is there a simple and straightforward way to provide a link in a view to either create a resource if it doesn't exist or edit the existing on if it does?
IE:
User has_one :profile
Currently I would be doing something like...
-if current_user.profile?
= link_to 'Edit Profile', edit_profile_path(current_user.profile)
-else
= link_to 'Create Profile', new_profile_path
This is ok if it's the only way, but I've been trying to see if there's a "Rails Way" to do something like:
= link_to 'Manage Profile', new_or_edit_path(current_user.profile)
Is there any nice clean way to do something like that? Something like the view equivalent of Model.find_or_create_by_attribute(....)
Write a helper to encapsulate the more complex part of the logic, then your views can be clean.
# profile_helper.rb
module ProfileHelper
def new_or_edit_profile_path(profile)
profile ? edit_profile_path(profile) : new_profile_path(profile)
end
end
Now in your views:
link_to 'Manage Profile', new_or_edit_profile_path(current_user.profile)
I came across this same problem, but had a lot of models I wanted to do it for. It seemed tedious to have to write a new helper for each one so I came up with this:
def new_or_edit_path(model_type)
if #parent.send(model_type)
send("edit_#{model_type.to_s}_path", #parent.send(model_type))
else
send("new_#{model_type.to_s}_path", :parent_id => #parent.id)
end
end
Then you can just call new_or_edit_path :child for any child of the parent model.
Another way!
<%=
link_to_if(current_user.profile?, "Edit Profile",edit_profile_path(current_user.profile)) do
link_to('Create Profile', new_profile_path)
end
%>
If you want a generic way:
def new_or_edit_path(model)
model.new_record? ? send("new_#{model.model_name.singular}_path", model) : send("edit_#{model.model_name.singular}_path", model)
end
Where model is your instance variable on your view. Example:
# new.html.erb from users
<%= link_to new_or_edit_path(#user) do %>Clear Form<% end %>
Try this:
module ProfilesHelper
def new_or_edit_profile_path(profile)
profile ? edit_profile_path(profile) : new_profile_path(profile)
end
end
and with your link like:
<%= link_to 'Manage Profile', new_or_edit_profile_path(#user.profile) %>

Resources