fabrik42/acts_as_api

Use current_user variable in template ?

Closed this issue ยท 8 comments

Hello,

I'm trying to get around the best way to add session data to my templates.

For instance, my user1 is requesting the profile of user2 with the user http://domain/users/2.json

My template looks like something like that :

api_accessible :default do |t|
t.add :id
t.add :name
t.add :avatar_image
t.add lambda{|u| u.following?(current_user)}, :as => :following
end

But the current_user variable is not available in the model. Is there a way around that with the current implementation of the gem ?

Thanks for your help !

Hi,

I guess you are talking about a helper method called current_user like it is used by devise.
You can't access them because the current_user method is defined on a controller while acts_as_api renders the template on a model.

The gem does not provide a workaround for this. In case you can't find a model-only solution you'll have to bridge it yourself.

I'm closing this ticket, as a don't see this as a problem caused by the lib.
However, if you need assistance solving your issue, feel free to contact me. :)

Best,

Chris

Hello,

As I see it, we can't make the current_user helper method available in the model without breaking the MVC convention.
However we could I guess, pass extra variables to the render_for_api methods so they are available ?

Something like this :
render_for_api :default, :json => @users, :root => :users, :variables => {:current_user => current_user}

But maybe there is a better "Rails Way" to do this ?

Sorry for the late answer :(

I also thought about passing variables a couple times, but I decided not to add it because:

  • You can pass the variables only at one point, and only all at once. Once you'll need different information for attributes this will get messy
  • What do you do with subresources?
  • In fact, it would also break MVC, but in a much less flexible way than a custom solution would.

I also have had this kind of problem and generally it think acts_as_api should not be responsible for gathering the data.
The approach above will create e.g. N+1 queries in sql databases. It would be better if you could determine it when you fetch the data and before you pass it to acts_as_api.

I hope this helps. :)

I have been doing something like this to show relavent data about the current user. Using neo4j.

response_hash = @post.as_api_response :show
if current_user
  if rel = current_user.rel_to(@post)
    response_hash[:rel] = rel.as_api_response :show

It works because as_api_response returns a simple hash, which can be added to.

@pehrlich ๐Ÿ‘

Hi,

in fact, most of the time I don't use acts_as_api in AR models anymore, but in minimal presenter classes instead. This is much clearer in the separation of concerns and you can add the current user pretty easy.

Here is a simple example, how this can be done:

# in app/presenters
class Presenter

  attr_accessor :proxy
  attr_accessor :current_user

  def initialize(proxy, options = {})
    @proxy = proxy
    current_user = options[:current_user] if options.has_key?(:current_user)
  end

end

class PostPresenter < Presenter

  extend ActsAsApi::Base
  acts_as_api

  delegate :title, :body,
    :to => :proxy

  api_accessible :default do |template|
    template.add :title
    template.add :body
    template.add :author_name
  end

  def author_name
    current_user.name
  end

end

# in your controller
PostPresenter.new(@post, current_user: current_user).as_api_response(:default)

I have a similar problem, but I want to limit the number of child associations in a template .i.e.

the limit would be a param. in the request if not present default value of 10

  api_accessible :v1_list do |template|
    binding.pry
    template.add :id
    template.add :parent_id
    template.add :client_id
    template.add :reference
    template.add :created_at
    template.add :updated_at
    template.add :closed_at
    template.add :subtype_id
    template.add :state
    template.add lambda{ |incident| incident.items.first(limit) }, :template => :v1_list, :as => :items
  end

So how can I add this, must I use presenter?, or I have any alternatives

Hi! You can pass options to as_api_response, see these examples.

They will get passed as the second argument to all lambdas.

So in your case it would work like this:

  MyModel.api_accessible :v1_list do |template|
    binding.pry
    template.add :id
    template.add :parent_id
    template.add :client_id
    template.add :reference
    template.add :created_at
    template.add :updated_at
    template.add :closed_at
    template.add :subtype_id
    template.add :state
    template.add lambda{ |incident, options| incident.items.first(options[:limit]) }, :template => :v1_list, :as => :items
  end

  MyModel.as_api_response(:v1_list, limit: 10)

I hope this helps!