Pergunta

I've been developing a web app in Rails 4, and used the Michael Hartl tutorial as the backbone for it, but using Devise as well. After building some of it, I went back and changed the Status model to be polymorphic in order to allow users, venues and groups to be able to post a status. I've got a certain way with this so far, but am now stuck. When trying to view a user's profile, I am currently getting this error:

NoMethodError in Users#show

Showing /home/app_name/app/views/users/show.html.erb where line #6 raised:

undefined method `avatar' for #<ActiveRecord::AssociationRelation::ActiveRecord_AssociationRelation_Status:0xb6859fd8>
Extracted source (around line #6):

<aside class="col-md-4">
  <section>
    <h1>
        <%= image_tag @user.avatar.url(:thumb) %>
    <%= @user.name %>
    </h1>
  </section>

The user definitely has an avatar, and as far as I can work out it seems to be having trouble working out the association through the polynomial relationship. It's on the user#show page, so presumably I shouldn't change "user" to "statusable", I have already tried this anyway, but don't understand where the problem is coming from. The profile shows a feed of statuses at present and an avatar for the user in each.

Any help would be greatly appreciated.

EDIT

Here are my user and status models:

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :omniauthable, :omniauth_providers => [:facebook, :twitter, :google_oauth2]

    before_save { self.username = username.downcase }

    validates :first_name,    presence: true, 
                              length: { maximum: 25 }
    validates :last_name,     presence: true, 
                              length: { maximum: 25 }
    VALID_USERNAME_REGEX = /\A[\w+\-._]+\z/i
    validates :username,      presence: true, 
                              length: { maximum: 20 },
                              format: { with: VALID_USERNAME_REGEX },
                              uniqueness: { case_sensitive: false }
    validates :email,             presence: true
    validates :password,      presence: true
    validates :birthday,      presence: true
    validates :gender,            presence: true
    validates :postcode,          presence: true
    validates_format_of :postcode, :with =>  /\A([A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW])\s?[0-9][ABD-HJLNP-UW-Z]{2}|(GIR\ 0AA)|(SAN\ TA1)|(BFPO\ (C\/O\ )?[0-9]{1,4})|((ASCN|BBND|[BFS]IQQ|PCRN|STHL|TDCU|TKCA)\ 1ZZ))\z/i, :message => "invalid postcode"

    has_attached_file :avatar, :styles => { :medium => "300x300", :thumb => "100x100", :micro => "30x30", :large => "500x500>" }, :default_url => "/images/:style/missing.jpg"
    validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/

    geocoded_by :address
    after_validation :geocode

    self.per_page = 20

    def address
      [town, postcode, country].compact.join(', ')
    end

    def feed
      Status.from_users_favourited_by(self)
    end

    def self.all_except(user)
      where.not(id: user)
    end
  end


    def name
        first_name + " " + last_name
    end

  has_many :statuses, as: :statusable, dependent: :destroy
  accepts_nested_attributes_for :statuses

end

class Status < ActiveRecord::Base
    before_create :set_latlong

    belongs_to :statusable, polymorphic: true

    default_scope -> { order('created_at DESC') }
    validates :content, presence: true, length: { maximum: 140 }
    validates :statusable_id, presence: true
    validates :statusable_type, presence: true

    def set_latlong
        self.latitude = statusable.latitude
        self.longitude = statusable.longitude
    end

    def self.from_users_favourited_by(user)
        favourited_user_ids = "SELECT favourite_id FROM favouriteusers
                                    WHERE favourited_id = :user_id"
        where("statusable_id IN (#{favourited_user_ids}) OR statusable_id = :user_id", user_id: user.id)
    end
end

Here is the Status controller:

    class StatusController < ApplicationController
  before_action :authenticate_user!, only: [:create, :destroy]
  before_filter :load_statusable

  def new
    @status = Status.new(status_params)
  end


  def create
    @statusable = load_statusable
    @status = @statusable.statuses.build(status_params)
    if @status.save
        flash[:success] = "Status created!"
        redirect_to root_url
    else
      @feed_items = []
        render 'static_pages/home'
    end
  end

  def destroy
    @status.destroy
    redirect_to root_url
  end

  private

    def status_params
        params.require(:status).permit(:content)
    end

    def load_statusable
      resource, id = request.path.split('/')[1, 2]
      resource_name = resource.singularize.classify
      if resource_name = "user"
        @statusable = current_user
      else 
        @statusable = resource_name.constantize.find(id)
      end
    end
end

And finally the status schema:

create_table "statuses", force: true do |t|
    t.string   "content"
    t.integer  "statusable_id"
    t.string   "statusable_type"
    t.float    "latitude"
    t.float    "longitude"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

I've taken a few bits out to make it easier to read, but hopefully have left in the bits needed.

EDIT

class UsersController < ApplicationController

before_filter :authenticate_user!, only: [:index, :show,:edit,
:update, :destroy, :favourite_users, :favourited_users]

def index

 @users = User.all_except(current_user).paginate(page: params[:page]).order('created_at DESC')

end


def show

   @user = User.find(params[:id])

   @user = @user.statuses.paginate(page: params[:page])

end


def new

 @user = User.new

end


def edit

   @user = User.find(params[:id])

end


def update

   @user = User.find(params[:id])

    if @user.update_attributes(user_params)

     # Handle a successful update.

    else

     render 'edit'

    end

end


def create

 @user = User.create( user_params )

end


def favourite_users

 @title = "Favourites"

 @user = User.find(params[:id])

 @users = @user.favourite_users.paginate(page: params[:page])

 render 'show_favourite'

end


def favourited_users

 @title = "Listed as a Favourite by"

 @user = User.find(params[:id])

 @users = @user.favourited_users.paginate(page: params[:page])

 render 'show_favourite'

end
Foi útil?

Solução

Well, it sure looks like @user does not contain a User but rather a ActiveRecord::AssociationRelation::ActiveRecord_AssociationRelation_Status. No wonder it doesn't have an avatar method! Check your controller code to see what @user is actually set to. If you can't make sense of what's going on, post the controller here. The User model and schema will probably be needed, too.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top