10

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(....)

Andrew
  • 42,517
  • 51
  • 181
  • 281

5 Answers5

31

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)
Douglas F Shearer
  • 25,952
  • 2
  • 48
  • 48
  • That works. I suppose creating a helper yourself is kind of obvious... and would explain why there doesn't appear to be a similar built-in function. Thanks! – Andrew Apr 11 '11 at 18:43
7

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.

Russell
  • 12,261
  • 4
  • 52
  • 75
5

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
  %>
krunal shah
  • 16,089
  • 25
  • 97
  • 143
1

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 %>
MurifoX
  • 14,991
  • 3
  • 36
  • 60
-4

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) %>
William Price
  • 4,033
  • 1
  • 35
  • 54