Display multiple images in rails_admin - ruby-on-rails

I am using rails_admin with Rails 5. I have a model Hotel with an association images (has_many). Currently I use the default config of rails_admin, and under Hotel show page, the images of a hotel are displayed in this format:
Image #5381, Image #5382, Image #5383, Image #5384, Image #5385,...
How can I display these images as a gallery given that each image has a thumbnail_url attribute? I means which config I could put in this block to change the display:
show do
field :images do
# Display as a gallery
end
end
Thanks for your time!

Rendering a custom partial is probably the best approach here. Something like:
field :images do
render do
bindings[:view].render partial: 'image_preview', locals: {object: self}
end
end
Then create the partial in app/views/rails_admin/main/_image_preview.html.*, and you're free to control what appears.

Related

Rails - save image to active storage using signature_pad js / toDataUrl canvas method

I am creating images using signature pad (signature pad allows the user to draw or "sign" and creates an image of the signature for you).
Signature pad creates an image using the toDataURL() javascript method (see here).
I'm trying to attach this image (which I am calling "signature") to my Doc model using an html.erb form and active storage.
Here is my model:
class Doc < ApplicationRecord
has_one_attached :signature
end
and here is a some of the html / javascript:
<%= f.hidden_field :signature, id: "signature_input", value: nil %>
<script>
// create image and attach to input field when the user submits the form.
// The ".toDataUrl()" create a data url image - this is where I'm struggling. I'm not familiar with data url images
$('#signature_input').val(signature_pad.toDataURL());
</script>
here's my controller (I think this is where I need to process the data url image and store with active storage... but I'm really struggling here)
class DocSignaturesController < ApplicationController
def update
# find doc
#doc = Doc.find(params[:id])
# assign the update params. NOTE: after assigning the "signature" the #doc will no longer be valid
#doc.assign_attributes(update_params)
# saving causes error: "ActiveSupport::MessageVerifier::InvalidSignature (ActiveSupport::MessageVerifier::InvalidSignature):"
#udoc_signature.save
end
private
def update_params
params.require(:doc).permit(:signature)
end
end
I think the way my form and javascript are set up, the "signature" image could be saved as a binary attribute on the Doc model directly to the database (I have not tried this, but this is what the tutorial I'm working through shows). However, with active storage, it is not working.
I've been able to upload images to active storage from other views (using rails f.file_field inputs) but I'm having trouble with the data url and f.hidden_field input.
Any help would be greatly appreciated!
Thanks

"Too many open files" error uploading with Paperclip

I'm using Rails 3.2.13 and Paperclip to upload/store images for a photo website. The form is nested for albums and photos. The Album model contains the lines
attr_accessible :photos_attributes
accepts_nested_attributes_for :photos
And the Photo model
has_attached_file :photo
So the form has an input
<input type="file" name="album[photos_attributes][][photo]" multiple="true">
It works perfectly for a few photos, but when I try to upload a ton, as a user might since it's a photo website, I get the error "Too many open files."
From what I read, it seems like it's because of the way Paperclip handles opening files and not closing them, so I need to manually close them? The Album#create controller action looks like this:
def create
#album = Album.new(params[:album])
if #album.save
redirect_to album_url(#album)
else
render :new
end
end
What do I need to add here to get this to work? Thanks in advance.

ActiveAdmin display default view content

I am working with ActiveAdmin and need to make customizations to some views and have come across a couple of scenarios I feel I am doing wrong.
I am adding an additional table to a show view (comments on Posts). This requires me to rewrite the whole attributes table and then add my panel. Is there a way to customize views without losing the default content?
I would also like to add a table of associated items on the show view which doesn't need to be customized is there any way to include the default tale that would normally be on the index view with default actions and paging?
After digging in the source code of Active Admin, I've found a way to patch this
show do
default_main_content
panel "Your Added Stuff" do
# Add stuff here
end
end
Of course this is undocumented and maybe considered a hack, but unless any other solution exists, it works.
Note: To do this in the form action (new and edit):
form do |f|
f.inputs
# Other inputs here
f.actions
end
Instead of using default_main_content, you could also just loop through the columns on the model like so:
ActiveAdmin.register Ad do
show do
attributes_table do
default_attribute_table_rows.each do |field|
row field
end
# Custom bits here
end
end
end
A couple areas of the documentation might help you:
See Customize the Show Page, Customizing the Index Page, Customizing the Form, and Custom Pages. An example of customizing a show screen:
ActiveAdmin.register Ad do
show do |ad|
default_main_content
h3 ad.title
end
end
See Custom Action Items in the Custom Controller Actions section of the documentation. An example:
action_item :only => :show, :if => proc{ current_admin_user.super_admin? } do
"Only display this to super admins on the show screen"
end
NB default_main_content does not exist in the documentation anymore, yet it works fine.
Just figured that out myself:
For the default table index page you can do something like this
index do
h1 "Hello World"
p "get more content"
instance_eval(&default_table)
end

Rendering polymorphic object in Rails

For people that only want the question, here it is :
Is there a way to specify the folder to look in when you call render on an object? I don't want to specify the view, only the folder to look in.
And for people that want context :
I am working on an activity stream system (something that looks like google+/facebook).
I have "Activities", which are exactly like google+ feeds (or facebook, or whatever!). So, I have a simple loop that display each activities, which are bound to one of the following object (polymorphic) : User, Group, Comment, Note.
In my view that render an activity (views/activities/_activity.html.erb), I have
<%= render activity.object %>
where activity.object is a reference to the bound object (User, Group, Note, Comment). If it's a user, it goes to views/users/_user.html.erb and renders it. For a group, views/groups/_group.html.erb.
That works just fine. However, I come to the point where the rendering of a group in my activities should not be the same rendering as in the group list page. Is there a way to specify the folder to look in when you call render on an object? So that my :
<%= render activity.object %>
would become :
<%= render activity.object, :folder => 'views/activities/' %>
Note that I don't want to specify which view directly, as I don't want to do a case for each of the possible types of objects (User, Group, Note, Comment) in the activity. I want to to have the same behaviour as of right now, which means if it finds a views/activities/_user.html.erb, it would load any user in the activities with that view instead of the one in the views/users/_user.html.erb.
Thanks
I'm not aware of any folder type option, but when I do this I usually do:
<%= render "activities/#{activity.object.class.name.underscore}" %>
That would give you similar behaviour.
EDIT A good point below by Dominic, if your classes are nested in namespaces, you will have to include the appropriate structure.
i.e.
module Foo
class Bar < ActiveRecord::Base
end
end
# class.name is Foo::Bar, underscored is 'foo/bar'
<%= render "activities/#{activity.object_type.underscore}" %>
# will be in
activities/foo/_bar.html
In current Rails (3.2.9), you can define a to_partial_path method on your model to tell it where to look.
For example, you can do:
class User
def to_partial_path; "user"; end
end
Rails will then look for _user.html.erb relative to the view from which you're calling render.
My own approach, which I extracted in polymorphic_render gem - to add suffixes for special partials, but store that partial in resource folders.
In your case views/users/_user.html.erb will have very common user representation (which probably used in users list rendering), but views/users/_user_activity.html.erb will render special partial for user activity.
And inserting that partials is very simple, just <%= polymorphic_render activity.object, :activity %>

Rails: Create a custom UI for a single specific object

I've run into a problem I'm completely unsure how to approach.
I have an app for sharing architectural photos. Users have_many Photos, and users can create Collections which also have_many Photos.
Now I have one customer who is a big name in the industry who would like to work with me to create a totally customized Collection with a very different look and feel from "regular" collections, but essentially the same functionality underneath. I'd like to accommodate this request, but I really have no idea how to do it.
Given that I already have a functioning Collection model and CollectionsController, plus all the views, I'd like to re-use as much of that as possible. So, for instance, the custom Collection needs to override the user facing :show view, but not the admin :edit view.
How would you approach something like this?
I'm trying to understand the most efficient, DRY method for creating a completely custom UI for a single record in the database. I'd be very appreciative of suggestions, including links to articles / books etc, as I haven't been able to find much in this area.
I would allow the creation of Liquid view templates associated with a User and/or Collection (if you want both - per-user templates with per-collection variations - use a polymorphic association) and of course fall back to your default view (also built with Liquid for consistency and reference) for all cases where no custom template is found.
Edit to add suggested details:
Any custom templates should be stored in the database (I would add a test/preview function so the user entering a custom template has the chance to verify their template before publishing it):
# Table name custom_templates
# id :integer
# templatable_type :string
# templatable_id :integer
# contents :text
class CustomTemplate < ActiveRecord::Base
belongs_to :templatable, :polymorphic => true
end
class User
has_one :custom_template, :as => :templatable
end
class Collection
has_one :custom_template, :as => :templatable
end
In your controller action, look for a custom template:
custom_template = #collection.custom_template
custom_template ||= #user.custom_template
#custom_template = Liquid::Template.parse(custom_template.contents) if custom_template
In your view, either render the custom template or your default template partial:
<% if #custom_template -%>
<%= #custom_template.render(_hash_of_objects_to_pass_to_liquid_template_) %>
<% else -%>
<%= render :partial => 'default' %>
<% end -%>

Resources