Rails: "new or edit" path helper? - ruby-on-rails

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) %>

Related

Delete an attachement (an avatar) with Devise

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

Ruby on Rails -- independant controller method for static pages

So basically I want to use a simple controller method with no params:
def create_message
#a = Message.create(:body => "Hello")
#a.save
redirect_to messages_path
end
but i'm routing from the home page, pages controller:
def home
end
I'm having a problem figuring out what to write in the routes file, I've tried almost everything including but not limited to:
resources :pages do
collection do
get :create_message
end
end
Views:
<%= link_to "Create Message", create_message_pages_path, class:"btn btn-primary"%>
Error:
The action 'create_message' could not be found for PagesController
You can create custom route for create_message like this
#routes.rb
get 'create_message' => 'pages#create_message', as: 'create_message'
Then link_to would be:
#view
<%= link_to "Create Message", create_message_path, class:"btn btn-primary"%>
I faced this problem once, in my case it is defining action under private block of controller gave the "The Action could not be found error". From your question I see there is no problem in defining routes and using it in view file. Please check to see if the create_message action is defined under private block in pages_controller.rb file. Hope it helps.

Rails link_to pass :id from show to another controller action

I'm viewing 1 product in show.html.erb and there's a link below that says "View other products from this company". This link_to connects to another non-restful action in same controller which retrieves from DB other products of same company as was shown in show.html.erb.
Can link_to pass the :id of the current product in show to action it's rendering? I'm new to rails and please let me know if question is not making sense. I'm not sure if routes need to be defined as well. Thanks.
products_controller.rb
def show
#company_products = Product.by_company
end
show.html.erb
<%= link_to "View other products from this company", company_products_path(:anchor => "#{#company_products}") %>
routes.rb
get '/company_products_' => 'products#company_products'
I finally resolved it by passing the :id of object in show via link_to to a non-restful action.
I'm open to suggestions if entire #company_products in #show can be passed as it is because I'm first finding if there are any other products for that company and if there are, passing an id only in link_to and in controller#company again running a query to get same data of all products to display. so running same query twice is not DRY.
controller#show remains the same as originally posted.
routes.rb
resources :products do
get :company, on: :member
end
show.html.erb
<%= link_to "View other products from #{#company_name}", company_product_path(#product.company_id) %>
controller#company
def company
#products_of_company = Product.where(company_id: params[:id])
end
Now in company.html.erb, the list is just displayed.
You want to do something like this:
#company_products.each do |company|
link_to "View other products from this company", products_path(company)
end
routes:
resources :products

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 would I make a link that takes you to a random article on the site?

It would be exactly like Wikipedia's "Random Article" button. Takes you to a random webpage on the site.
<%= button_to "Random Article", article_path(random_article) %>
#app/helpers/application_helper.rb
class ApplicationHelper
def random_article
Article.order("RAND()").first.pluck(:id)
end
end
With help from this article: Random record in ActiveRecord
Some more information would make this much easier to answer, but there are a few ways to do it. The best, in my opinion, would be something like this:
routes.rb:
resources :articles do
get :random_article
end
#OR
get 'random_article' => 'some_controller#random_article', as: 'random_article'
articles_controller.rb
def random_article
redirect_to article_path(Article.all.sample.id)
end
And on your page:
<%= link_to 'Random Article', random_article_path %>

Resources