I'm building a simple rails application where users can upload some images. Now I need a simple controller that returns the image's URLs of related record which have the same id_attivita. To do so I create a function in the controller and enable it in the routes.rb file.
My question is about how to respond to the http request with the attribute value of image.url provided from paperclip?
def getattached
#photo_attivitum = PhotoAttivitum.where(id_attivita: params[:id_attivita])
respond_to do |format|
#photo_attivitum.each do |p|
format.html { render :json => p.image.url}
end
end
end
it works but it returns only the URLs of the first record not the other four record's URLs...
How can I do this?
Add the following gem to your Gemfile
gem 'active_model_serializers'
Then install it using bundle
bundle install
You can generate a serializer as follows
rails g serializer photo_attivitum
it will create Serializer class file in
# app/serializers/photo_attivitum_serializer.rb
class PhotoAttivitumSerializer < ActiveModel::Serializer
attributes :id, :image_url
def image_url
object.image.url
end
end
And in controller
def getattached
#photo_attivitum = PhotoAttivitum.where(id_attivita:
params[:id_attivita])
render json: #photo_attivitum
end
Not sure what u want to do? Show all image urls in json?
urls = #photo_attivitum.pluck('image_url')
format.html { render :json => urls}
Related
I have a problem with rendering array properly with JBuilder on Rails 6 (API only mode).
I basically have a list of registration plates, which I want to fetch via API request
My index view looks like this:
# frozen_string_literal: true
json.array! #registration_plates,
partial: 'registration_plates/registration_plate',
as: :registration_plate
My show view looks like:
# frozen_string_literal: true
json.partial! 'registration_plates/registration_plate',
registration_plate: #registration_plate
And finally partial _registration_plate.json.jbuilder is very simple:
# frozen_string_literal: true
json.id registration_plate.id
json.plate registration_plate.plate.to_s
I do get a normal response from server:
But instead of an array, I get the series of JSON objects
Did anyone have similar problem, or do you have any idea how to solve it?
Than you in advance.
EDIT
Also my controller is configured to render the jbuilder rather than json
# GET /registration_plates
def index
#registration_plates = RegistrationPlate.all
render #registration_plates
end
# GET /registration_plates/1
def show
render #registration_plate
end
And if I change the index action to look like
def index
#registration_plates = RegistrationPlate.all
render json: #registration_plates.to_json(only: %i[id plate])
end
i do get correct output, but then, I defy the sole purpose of jbuilder
update your index to remove render #registration_plates
# GET /registration_plates
def index
#registration_plates = RegistrationPlate.all
end
render #registration_plates renders _registration_plate.json.jbuilder directly without going into index.json.jbuilder
I am using Carrierwave to upload an image from a remote url :
def save
uid = SecureRandom.uuid
storedir = "uploads/#{uid}"
image = Image.new
image.image.store_dir = storedir
image.remote_image_url = "a remote url here"
if image.save!
respond_to do |format|
format.js
format.json { render json: {:saved => "#{image.image_url}", :id => "#{image.id}"} }
end
end
end
the returned result is correct :
Object { saved="https://mybucket.s3-eu-west-1.amazonaws.com/uploads/58406672-c227-4cec-a846-04c443e70f33/thumb_yr169-ae2f3bc4-74f4-47ee-950c-2e06756525b9-v2.png", id="47"}
As you can see the image url is this :
https://mybucket.s3-eu-west-1.amazonaws.com/uploads/58406672-c227-4cec-a846-04c443e70f33/thumb_yr169-ae2f3bc4-74f4-47ee-950c-2e06756525b9-v2.png
and when I go to check the file, it's there in the right folder, but when I go to the Rails Console and look for that record, the result of image_url is wrong :
> Rails console
> Image.find(47).image_url
> https://mybucket.s3-eu-west-1.amazonaws.com/uploads/thumb_yr169-ae2f3bc4-74f4-47ee-950c-2e06756525b9-v2.png
The uid after /uploads/ is gone!!
any help please!!
UPDATE
Looks like carrierwave is go check store_dir in the uploader to show the image url, in my case I override it before saving the image, and I would like to use that custom store_dir
Yeah, that is because CarrierWave, like most similar libraries try to build your url dynamically.
Add this to your ImageUploader
#ImageUploader
def uid
'58406672-c227-4cec-a846-04c443e70f33'
end
def store_dir
"uploads/#{uid}"
end
#XController
def save
image = Image.new
image.remote_image_url = "a remote url here"
if image.save!
respond_to do |format|
format.js
format.json { render json: {:saved => "#{image.image_url}", :id => "#{image.id}"} }
end
end
end
UPDATE
Not totally sure of why you'd want to overide the store, but in order to do that, I think you may be better served by storing the additional details on the images table as such:
Add a column to your Image model, which may be the store_uid
In your ImageUploader, change your store_dir to use your builder or the field name, e.g if the column on Image is store_uid, with value: whatever-uid-has-been-stored-here, you could do:
def store_dir
# /uploads/whatever-uid-has-been-stored-here
"uploads/#{model.store_uid}"
end
A cleaner approach and one that's often advised is to create another uploader for each kind of images, for consistency within your application
I have the model that uses paperclip like this
has_attached_file :image, styles: { :medium => "50x50>" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
def image_url
image.url(:medium)
end
I need it Json, So in my controller,
respond_to do |format|
format.json { render json: #celebrity.to_json(:methods => [:image_url])}
end
And the result is
"image_url":"/system/celebrities/images/000/000/003/medium/Designed___developed_by_wd_ApS.png?1430926991"
but, I need to include the domain name, localhost:3000 ,
So what I have to do here
Try this.
Create module:
module WithDomain
def domain
#domain
end
def domain=(val)
#domain = val
end
def domain?
#domain.present?
end
end
Change you model accordingly:
class Celebtiry < ActiveRecord::Base
include WithDomain
# existing staff
def image_url
if domain?
URI.join(domain, image.url(:medium)).to_s
else
image.url(:medium)
end
end
end
and in your controller:
respond_to do |format|
format.json {
#celebrity.domain = request.base_url
render json: #celebrity.to_json(:methods => [:image_url])
}
end
Solution 1: (with existing code)
You can use asset_url from ActionView::Helpers::AssetUrlHelper module which will give you the absolute url of your image. Just include ActionView::Helpers::AssetUrlHelper this in your model so that asset_url becomes available inside your model.
So, your method inside the model would be:
include ActionView::Helpers::AssetUrlHelper
def image_url
asset_url(image.url(:medium))
end
This is the easiest solution for you with your current code.
Solution 2: (inside the controller)
In your controller request is available, so you can do:
URI.join(request.url, #celebrity.image.url(:medium))
which will give you the absolute url of the image. This will be an URI object, which can be converted to a String with .to_s method.
Here is the issue from paperclip from where this solution is derived. Hope this helps.
I'd like a Rails controller (all of them, actually, it's an API) to render JSON always always.
I don't want Rails to return "route not found", or try and fail to find an HTML template, or return 406. I just want it to automatically and always render JSON, e.g. from a RABL or JBuilder view.
Is this possible? Related questions seem to have answers that have the aforementioned downsides.
You can add a before_filter in your controller to set the request format to json:
# app/controllers/foos_controller.rb
before_action :set_default_response_format
protected
def set_default_response_format
request.format = :json
end
This will set all response format to json. If you want to allow other formats, you could check for the presence of format parameter when setting request.format, for e.g:
def set_default_response_format
request.format = :json unless params[:format]
end
You can use format.any:
def action
respond_to do |format|
format.any { render json: your_json, content_type: 'application/json' }
end
end
It's just:
render formats: :json
I had similar issue but with '.js' extension. To solve I did the following in the view:
<%= params.except!(:format) %>
<%= will_paginate #posts %>
I tried the above solutions and it didn't solve my use case.
In some of the controllers of my Rails 4.2 app, there was no explicit render called. For example, a service object was called and nothing was returned. Since they are json api controllers, rails was complaining with a missing template error. To resolve I added this to our base controller.
def render(*args)
options = args.first
options.present? ? super : super(json: {}, status: :ok)
end
It's a large app I'm converting to Rails 5, so this is just a safety measure as I removed the RocketPants gem that seemed to do this automatically.
As a note, my controllers inherit from ActionController::Base
Of course:
before_filter :always_json
protected
def always_json
params[:format] = "json"
end
You should probably put this in a root controller for your API.
My setup: Rails 2.3.10, Ruby 1.8.7
I have experimented, without success, with trying to access a virtual attribute in a model from a JSON call. Let's say I have the following models and controller code
class Product
name,
description,
price,
attr_accessor :discounted_price
end
class Price
discount
end
class ProductsController
def show
#product = Product.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #product }
end
end
end
What I like is to have the JSON output also include Product.discounted_price which is calculated in real-time for each call, ie discounted_price = Price.discount * Product.price. Is there a way to accomplish this?
SOLUTION:
With the initial help from dmarkow, I figured it out, my actual scenario is more complex than the above example. I can do something like this, in the Product model, add a getter method
def discounted_price
...# do the calculation here
end
In the JSON call do this
store = Store.find(1)
store.as_json(:include => :products, :methods => :discounted_price)
You can run to_json with a :methods parameter to include the result of those method(s).
render :json => #product.to_json(:methods => :discounted_price)
Have a look at the gem RABL, as shown in this railscast:
http://railscasts.com/episodes/322-rabl?view=asciicast
RABL gives you fine grained control of the json you produce, including collections and children.