0

We have a requirement where a user needs to select their avatar for their profile. On the edit profile page, the user clicks on a Change Picture link which takes them to another page and gives them with two links to get their photo from facebook or gravatar. There is also a preview of the image shown on this page, as well as a save button. The controller for this page is AvatarsController. I have edit and update actions, as well as custom GET actions for facebook and gravatar, so that the route looks like avatar/facebook, and avatar/gravatar. These actions simply query the respective services and create a new avatar model containing the url for the photo. When the user clicks save, the update action is called and the avatar model is saved with the profile. The page is delivered by the edit template, as by default, when a user is created, an empty avatar is also created.

The Profile model (using mongoid) essentially looks like:

def Profile
  embeds_one :avatar
end

and the avatar model looks like:

def Avatar
  embedded_in :profile
end

The route looks like:

resource :avatar, only: [:edit, :update] do
   member do
     get 'facebook'
     get 'gravatar'
   end
end

The controller looks like:

class AvatarsController < ApplicationController
  def facebook
    url = AvatarServices.facebook(current_user, params[:code])
    respond_to do |format|
      unless url
        format.json { head :no_content }
      else
        @avatar = Avatar.new({:url => url, :source => "Facebook"})
        @avatar.member_profile = current_user.member_profile
        format.html { render :edit }
        format.json { render json: @avatar }
      end
    end
  end
  def gravatar
    respond_to do |format|
      url = AvatarServices.gravatar(current_user)
      unless url 
        format.json { head :no_content }
      else
        @avatar = Avatar.new({:url => url, :source => "Gravatar"})
        @avatar.member_profile = current_user.member_profile
        format.html { render :edit }
        format.json { render json: @avatar }
      end
    end
  end
  def edit
    @avatar = current_user.member_profile.avatar
  end
  def update
    @avatar = current_user.member_profile.avatar
    respond_to do |format|
      if @avatar.update_attributes(params[:avatar]) 
        format.html { redirect_to edit_member_profile_path }
        format.json { head :no_content }
      else
        format.html
        format.json { render json: @avatar.errors }
      end
    end
  end
end

This works, but being fairly new to rails, I'm wondering if rails experts would have set up the 'facebook' and 'gravatar' resources differently, perhaps in a more RESTful manner?

stantona
  • 3,260
  • 2
  • 24
  • 28

2 Answers2

1

Well, the subfolder is putting the facebook and gravatar controllers into a common namespace. You could use nested routes,

resource :avatar, only: [:edit, :update] do
  resource :facebook
  resource :gravatar
end

This will route to a FacebooksController and a GravatarsController.

This is kind of what you were thinking anyway, and you won't need a record id for a facebook or gravatar record.

Marlin Pierce
  • 9,931
  • 4
  • 30
  • 52
0

Could you add your controller code? I'm interested to see how you have your actions setup.

If you want to keep things restful, it might just be a matter of creating a controller subfolder for avatars, and created subsequent controllers for gravatar & facebook. You can do this just using a generator

rails g controller avatars/facebook
rails g controller avatars/gravatar
agmcleod
  • 13,321
  • 13
  • 57
  • 96
  • Just added the controller. I was thinking along the same lines too, a controller for each service. But then I thought that the facebook and gravatar images are still resources of avatar that belong to the user, only they are just queried from an external service. – stantona Apr 24 '12 at 15:33