5

I have a rails app that consists of a CMS system that I use in order to enter sights from a city to my database. I am using paperclip to upload images to amazon s3. All is working fine. Now I want my json files that an ios app will use to include the urls of the images uploaded in s3. I have seen some answers here but I cannot seem to make my code work. What I have is this..

place model

attr_accessible :assets_attributes, :asset
has_many :assets
accepts_nested_attributes_for :assets, :allow_destroy => true

def avatar_url
   assets.map(&:asset_url)
end

asset model

class Asset < ActiveRecord::Base
  attr_accessible :asset_content_type, :asset_file_name, :asset_file_size, :asset_updated_at, :place_id, :asset
  belongs_to :place
  has_attached_file :asset

   validates_attachment :asset, :presence => true,
  :content_type => { :content_type => ['image/jpeg', 'image/png'] },
  :size => { :in => 0..1.megabytes }

def asset_url
    asset.url(:original)
    end

end

view code

<%= f.fields_for :assets do |asset_fields| %>

<% if asset_fields.object.new_record? %>
<p>
    <%= asset_fields.file_field :asset %>
</p>
<% end %>

<% end %>
<br/>

<%= f.fields_for :assets do |asset_fields| %>

<% unless asset_fields.object.new_record? %>


<%= link_to image_tag(asset_fields.object.asset.url(:original), :class => "style_image"), (asset_fields.object.asset.url(:original)) %>
    <%= asset_fields.check_box :_destroy %>

<% end %>

<% end %>

places controller

def index
    @places = Place.all
render :json => @places.to_json(:methods => [:avatar_url])
  end

Can anyone please help me?

user3077352
  • 55
  • 1
  • 7
  • Can you explain what you're looking for specifically from json? Do you want the Paperclip image object delivered back to display it, or a success / failure callback? – Richard Peck Dec 07 '13 at 11:31
  • The json for every place now doesn't include the url of the image that belongs to the place. I want this url to come with the json as well. – user3077352 Dec 07 '13 at 11:33
  • I have seen answers such as this http://stackoverflow.com/questions/5588185/how-can-i-get-url-for-paperclip-image-in-to-json but I can't make it work – user3077352 Dec 07 '13 at 11:34
  • Okay, so to get this straight -- you're uploading via an iOS app, and want the controller to return a JSON object with all the places? I'm just trying to get my head around the issue here :) – Richard Peck Dec 07 '13 at 11:35
  • No, no.. Maybe I am not putting it in the right form. You can forget the iOS app. I am uploading through my CMS system and everything is fine. In my views I can even see my uploaded images. I also create json files through the places controller (index method) that are accessible from an iOS app. Now what I want is in this json that is constructed for every place, the url of the image to be included. Just like the example I sent. – user3077352 Dec 07 '13 at 11:42
  • Any ideas? Please I could use some help – user3077352 Dec 08 '13 at 11:04
  • Hey sorry about the lack of reply! Okay I just looked at the reference you gave us -- I actually remembering copying it when I was starting out with Rails (learning the ropes), and it worked pretty well – Richard Peck Dec 08 '13 at 11:38
  • I'll write an answer to demonstrate some of the important elements for yu – Richard Peck Dec 08 '13 at 11:39

1 Answers1

8

In reference to the SO question you linked to (How can I get url for paperclip image in to_json), there are certain elements you'll need in order to get the image to render correctly

The problem you have is Paperclip's image method is actually an ActiveRecord object, and therefore you cannot just render it in a JSON request without doing some other stuff


The _url Method

The most important part of the process is to define the "_url" method in your asset model. This basically calls the .url function of Paperclip, allowing JSON to create the desired URL of the image on the fly (The url of the image is not an ActiveRecord object, and can therefore be sent via JSON)

As per the referenced SO question, you should put this action in your model:

#app/models/asset.rb
def asset_url
    asset.url(:medium)
end

Now when you render the JSON request in your controller, you can use this type of setup:

#app/controllers/places_controller.rb
render :json => @places.to_json(:methods => [:asset_url])

Because your asset model is an associate of places, this might not work straight away. However, it's definitely in the right direction, because I can remember doing this exact thing myself

The important thing to note here, is that you're actually passing the naked "URL" of the image through JSON, not the image object itself


Update

Here's an example from our video conference demo app we made:

#app/controllers/profiles_controller.rb
def update
   @profile = User.find(current_user.id)
   @profile.profile.update(upload_params)

   respond_to do |format|
      format.html { render :nothing => true }
      format.js   { render :partial => 'profiles/update.js' }
      format.json { render :json => @profile.profile.as_json(:only => [:id, :avatar], :methods => [:avatar_url])
      }
    end
end

   #app/models/profile.rb
   def avatar_url
       avatar.url(:original)
   end

So for you, I'd try this:

def index
    @places = Place.all
    render :json => @places.assets.as_json(:only => [:id, :asset], :methods => [:asset_url])
end

You could also try something like this:

#app/models/profile.rb
def avatar_url
   self.asset.avatar.url(:original)
end
Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • This is exactly what I want, the url of the image. I will try it and come back with a response. Thank you very much for your reply. – user3077352 Dec 08 '13 at 11:54
  • Unfortunately that doesn't seem to work. Although no error message appears the JSON doesn't contain any url. When I visit ...places.json the url is nowhere to be found. – user3077352 Dec 09 '13 at 15:30
  • I have edited my code above adding the asset_url method in asset.rb and altering the places_controller. However my JSON still doesn't contain the desired urls. I am thinking that maybe I should call the instance method asset_url from place.rb and then call the new method (from place.rb) in the places_controller but I can't make it work. Any help please? – user3077352 Dec 10 '13 at 09:57
  • Let's have a look again (sorry for lack of reply - I totally forgot about this!) – Richard Peck Dec 10 '13 at 09:58
  • No need for apologizing. I am grateful that you are trying to assist me. – user3077352 Dec 10 '13 at 09:59
  • Okay, I remember where we used the `methods` thing before - http://video-conference-demo.herokuapp.com (register & try to upload a profile image). I'll update my answer with what we did – Richard Peck Dec 10 '13 at 10:14
  • When I alter my code to what you proposed I get an error {"status":"500","error":"undefined method `asset' for #\u003CActiveRecord::Relation::ActiveRecord_Relation_Place:0x007fce6dca3418\u003E"} when visiting ...places.json – user3077352 Dec 10 '13 at 10:28
  • Try changing `asset` to `assets` (as per the `has_many` relationship). Sorry - my mistake – Richard Peck Dec 10 '13 at 10:29
  • Still when editing my code to render :json => @places.assets.as_json(:only => [:id, :asset], :methods => [:asset_url]) I get the error {"status":"500","error":"undefined method `assets' for #\u003CActiveRecord::Relation::ActiveRecord_Relation_Place:0x007f1003c5b1c8\u003E"}. Is it possible that I have to call the asset_url from the place.rb? – user3077352 Dec 10 '13 at 10:39
  • I am just not sure how to. How do I call an instance method of the asset.rb in the place.rb? – user3077352 Dec 10 '13 at 10:41
  • I am really sorry but you lost me. Maybe I am just too confused but I didn't get it. What am I changing? Again sorry for the details that I am asking but this is bothering me for two days. – user3077352 Dec 10 '13 at 10:50
  • No problem! I want this to work now. The problem I can see is that you're calling associative data, and so you have to design the response around that. The update I posted was right at the bottom of my answer (which probably won't work, but will give you some ideas). I would be looking at the JSON response, and more specifically how you're calling the `@places` variable, to ensure the associative data is handled correctly – Richard Peck Dec 10 '13 at 10:53
  • I reedited my code in place.rb, asset.rb and places_controller and now the error I am getting is {"status":"500","error":"undefined method `asset_url' for #\u003CActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_Asset:0x007f3a9c3076a8\u003E"}. – user3077352 Dec 10 '13 at 11:04
  • Okay that is good, because it means we were right to put `asset_url` in the `asset` model. Can you do a test, and instead of `@places = Place.all`, can you do `@places = Place.find(AN_ID_HERE)`? – Richard Peck Dec 10 '13 at 11:08
  • Sure just give me a second. – user3077352 Dec 10 '13 at 11:09
  • Now when I edit my places_controller to @place = Place.find(18) render :json => @place.to_json(:methods => [:avatar_ur]) I get no error but the url is nowhere. I just get the other info of the place 18 in JSON format. – user3077352 Dec 10 '13 at 11:16
  • Sorry, my fault still the same error {"status":"500","error":"undefined method `asset_url' for #\u003CActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_Asset:0x007f3c167106c0\u003E"} – user3077352 Dec 10 '13 at 11:34
  • I don't now if it helps but if I alter my code in place.rb to def avatar_url Asset.new.asset_url end the JSON for the place 18 returns (after all the other info of the place) "avatar_url":"/assets/original/missing.png". No error in finding asset_url now. – user3077352 Dec 10 '13 at 11:40
  • `def avatar_url Asset.new.asset_url` is giving the result you want! The only problem is that in creating a new `Asset`, you've not got any image associated with it. We need to work out how to call the method on the assets being called from the database – Richard Peck Dec 10 '13 at 11:59
  • Yes that is what I think also. I am trying to think of something – user3077352 Dec 10 '13 at 12:07
  • Had any luck with it yet? – Richard Peck Dec 10 '13 at 12:42
  • Unfortunately not. I am reading things about model associations but no luck yet. I can't come up with an idea of how to pass the instance method asset_url to the place 18 – user3077352 Dec 10 '13 at 12:49
  • I think it's to do with how you're calling assets_url -- it either needs to be in `place.rb` or `asset.rb`, and needs to reference the correct object (I.E `self.asset.asset_url`) – Richard Peck Dec 10 '13 at 12:52
  • I am trying different things and I wille let you know if I get a different response. Maybe then we can make something out – user3077352 Dec 10 '13 at 13:01
  • I tried a different approach and this time I am getting the error {"status":"500","error":"undefined method `url' for #\u003CAsset:0x007fd75639fc30\u003E"}. The approach is on my code above. This time I am reaching the asset.rb class method asset_url but then the url method is not recognized. Any ideas on this? – user3077352 Dec 10 '13 at 14:35
  • Okay thanks for trying something new! I can say your error is caused by you not using Paperclip correctly. The `.url` method is only applicable on a Paperclip object (I.E `variable.asset.url`). Although your way was lovely & creative, it is not a Paperclip object, and consequently will cause that error :( – Richard Peck Dec 10 '13 at 16:07
  • No problem! Are you going to try anything else? – Richard Peck Dec 10 '13 at 16:18
  • Finally we have the solution and I will edit my code in a minute. – user3077352 Dec 10 '13 at 16:21
  • Ohhhh nice. I am really excited to see! You've done well persisting this far – Richard Peck Dec 10 '13 at 16:21
  • I made with your help and other developers' help here in stackoverflow. Thank you very much for your time and effort – user3077352 Dec 10 '13 at 16:24
  • No problem - can you explain how you fixed it? – Richard Peck Dec 10 '13 at 16:26
  • Nice! I think it can be done more efficiently, but it's great that it's working! Maybe you'd want to accept my answer as I'm sure it helped? – Richard Peck Dec 10 '13 at 16:41
  • Thanks a lot. The same to you too – user3077352 Dec 10 '13 at 18:20
  • @RichPeck another time-saving answer! Once again, thanks! – Sylar Oct 21 '15 at 08:25