Ruby On Rails 35
Tutorial de Infinite Scrolling en Rails
Infinite scrolling es una técnica que consiste que a medida te acerques al final de la página esta cargue nuevos datos y sirve para remplazar la componente típica de paginación, el si es recomendable implementarla o no en una página es un tema bien discutido en la internet, pero en este tutorial vamos a explicar como implementarla.
Paso 0: Setup
Partamos con una aplicación vacía de Ruby on Rails, y dentro haremos el scaffold del recurso Post que contendrán los campos title y content.
Paso 0.1: Desacoplar el index
En lugar de ocupar el archivo index creado por el scaffold vamos a ocupar una vista parcial que contenga la información de cada post, de esta forma vamos a poder hacer mucho más con menos código.
Así que crearemos la vista parcial _post.html.erb
<!— views/posts/_post.html.erb → <%= div_for(post) do %> <h2><%= post.id %></h2> <h2><%= post.title %></h2> <p><%= post.content %></p> <% end %>
Luego el archivo posts/index.html.erb queda de esta forma:
<div id="content"> <%= render(partial: 'post', collection: @posts) %> </div>
Paso 1: Instalar la gema Kaminari para la paginación
¿Por qué necesitamos una gema para la paginación?, La respuesta es simple, para escribir menos código, las gemas de paginación nos separan los resultados en grupos, dependiendo de la página, la página 0 (sin número) contiene los primeros x resultados, la segunda página (?page=2) contiene los segundos x resultados. El truco que haremos con infinite scrolling es ir llamando via AJAX a estas distintas páginas generadas por el paginador (Kaminari)
Para instalar la gema hay que abrir el gemfile y agregar la línea
gem 'kaminari'
Paso 2: Paginando
Para paginar tenemos que modificar el controller de posts para especificar que los resultados deben ser paginados, esto lo hacemos modificando el método index.
def index @posts = Post.page(params[:page]).per(5) end
Paso 2.1 Link a la siguiente página
En la vista de posts simplemente haremos un link a la página siguiente, para eso ocuparemos el helper de rails url_for sólo especificando el query string page, o sea este método llamará a la misma página pero añadiendo ?page=2 (o 3, o 4, u otro valor dependiendo del caso)
<p id="view-more"> <%= link_to('Ver Más', url_for(page: @posts.current_page + 1)) %> </p>
Paso 3: Agregando datos
Hasta el momento nuestro sitio es un simple listado de posts páginado pero debería estar funcionando, para probarlo vamos a agregar datos ocupando el archivo seeds.rb y una gema espectacular para este propósito llamada Faker.
Paso 3.1: Agregar la gema Faker al gemfile y luego correr bundler
Paso 3.2: Agregar las siguientes líneas al archivo db/seeds.rb
50.times.each do |x| Post.create(:title => Faker::Lorem.sentence, :content => Faker::Lorem.paragraph ) end
paso 3.3: Correr rake db:seeds
paso 3.4: Probar entrando a localhost:3000/posts y ver los resultados, hacer click en siguiente y ver que la paginación funciona.
Paso 4: Infinite Scrolling
Hay librerías que podemos descargarde infinite scrolling, pero con Jquery es posible hacer el efecto de forma sencilla en sólo un par de líneas de código, para hacerlo vamos a crear el archivo scrolling.js.coffee dentro de la carpeta app/assets/javascript
Dentro del archivo vamos a hacer la primera prueba
jQuery -> $(window).scroll -> if $(window).scrollTop() > $(document).height() — $(window).height() — 50 alert("Final de la página")
al correr el sitio e ir al final de la página va a aparecer una alerta diciendo Final de la página, el valor -50 debera ser ajustado en casos especiales, como fixed footers que sean muy grandes.
Paso 4.2 Haciendo el llamado Ajax
Ahora vamos a ocupar la idea anterior pero cada vez que se llegue al final de la página vamos a cargar una página nueva con posts más antiguos, para eso el método $.getScript() de jquery a lo que el controller responderá con un archivo index.js.erb con los posts nuevos (al pedir un archivo javascript el controller devuelve lo pedido y lo ejecuta)
jQuery -> $(window).scroll -> url = $('#view-more a').attr('href') if url && $(window).scrollTop() > $(document).height() — $(window).height() — 50 $("#view-more").attr('href', '') $.getScript url
Lo último que falta es aprovechar el archivo javascript devuelto y utilizarlo para actualizar la página.
Paso 4.3 Cargando los posts.
El archivo devuelto, que todavía no hemos creado, es index.js.erb (siguiendo las convenciones de rails debe llamarse igual que el método), ahora creemos el archivo y dentro de el carguemos la vista parcial de post con la información de los nuevos post y actualizemos el link para que cargue posts aún más antiguos.
$('#content').append("<%= j render @posts %>"); $("#view-more").attr("href", "<%= j posts_path(page: @posts.current_page + 1) %>");
Y con eso logramos Infinite Scrolling
Happy Infinite Scrolling !!!
Paso 4.4 (Opcional, pero elegante): Removiendo el link al final del documento.
Para remover el link tenemos que saber si realemente estamos al final, para eso comparamos @posts.current_page == @posts.total_pages
$('#content').append("<%= j render @posts %>");
<% if @posts.current_page == @posts.total_pages %> $('#view-more').remove(); <% else %> $('#view-more').html("<%= j link_to('View More', url_for(page: @posts.current_page + 1)) %>"); <% end %>
“My Concerts Wishlist” ajax scaffold Ruby on Rails
Esta es una aplicación basada en un scaffold, sin embargo el CRUD está modificado para responder a peticiones Ajax en Rails.Comencemos con el paso a paso! la app la he llamado “My Concerts Wishlist”
StreetmusicMap parte 2: Integración Gmaps4Rails
Rubystas! Lo prometido aquí está. La segunda parte del tutorial del StreetMusicMap. Si quieres revisar la parte 1 de la historia, en donde explico como crear una relación uno a muchos uniendo 2 scaffolds “Musician” e “Instrument” te dejó por aquí el artículo.
En la segunda parte, vamos a integrar esa data que guardamos a traves del scaffold creado, para visualizarla de una forma entretenida e interactiva usando la gema gmaps4Rails.
Te sugiero que vayas por una buena taza de café antes de comenzar.
Instalando la gema geocoder.
Vamos a agregar la gema geocoder en mapa/Gemfile:
gem 'geocoder'
Luego en el terminal:
$ bundle
y reiniciamos el server con:
$ rails s
Geolocalizando a partir del campo “address”.
Abres app/models/Musician.rb y agregas esta línea:
class Musician < ActiveRecord::Base belongs_to :instrument geocoded_by :address after_validation :geocode end
En http://locahost:3000/musicians/new agregraremos 2 nuevos registros, dejamos vacíos los campos “latitude” y “longitude” . Luego te darás cuenta que al presionar “create musician” automáticamente se agregan valores. “Santiago Chile” en el campo address, obtendremos “-33.4367933” en latitude y “–70.64107299999” en longitude.
Geocoder es responsable de devolver las coordenadas como “Response” a partir de nuestra “Request” solicitada…Interesante..cierto?
pd: si no sabes por qué aparece este belongs_to:instruments quizás necesitas revisar la parte 1 del tutorial en donde explico todo eso)
Instalando la gema Gmaps4rails.
Vamos a agregar la gema gmaps4rails en mapa/Gemfile:
gem 'gmaps4rails'
Luego en el terminal:
$ bundle
y reiniciamos el server con:
$ rails s
Agregando algunas referencias .js en la vista parcial application.html.erb.
Abrimos el archivo app/views/application.html.erb y agregamos el js de bootstrap, googlemap api y markerclustered ántes de </head>
<!-- bootstrap 3--> <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script> <!-- google maps --> <script type="text/javascript" src="//maps.googleapis.com/maps/api/js?v=3.13&sensor=false&libraries=geometrykey=AIzaSyBX2Veo_ENuSNEXA3fdZS54WAOA9_wrm-Y"> </script> <!-- markerClustered --> <script src='//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js' type='text/javascript'></script>
Agregando el div “Map” en fullScreen con Bootstrap.
Para dibujar el mapa en modo fullscreen (en cualquier dispositivo) me basé en este ejemplo disponible en Bootstrap examples.
No fue exactamente un copyPaste del ejemplo…tuve que modificar un poquito siguiendo estos pasos para adaptarlo a nuestro propósito.
Primero, agrega una referencia minificada de bootstrap.min.css antes de todas las referencias .js que incluimos en app/views/application.html.erb
<!-- Latest compiled and minified CSS --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
Segundo, descargas el archivo cover.css y lo guardas en app/assets/stylesheets/cover.css
Tercero, buscas la linea en cover.css :
@media (min-width: 992px) { .masthead, .mastfoot, .cover-container { width: 700px; } }
y la reemplazas por esta otra:
@media (min-width: 992px) { .masthead, .mastfoot, .cover-container { width: 100%; } }
Tercero, abres app/views/musicians/index.html.erb y dibujamos el <div id=”map”> que cargará el contenido de nuestro google map tal como la imagen
<!-- contenedor del mapa --> <div class="site-wrapper"> <div id="map" class="site-wrapper-inner"> <div class="cover-container"> </div> </div> </div> <!--//fin contenedor mapa--> <!-- footer --> <div class="container-fluid"> <div class="row"> <div class=" col-lg-12 mastfoot"> <div class="inner"> <p>street music map <%= link_to 'New Musician', new_musician_path %> </p> </div> </div> </div> </div> <!-- //fin footer-->
Musician Controller: Cargando los datos en el objeto @Hash.
En el controller musician en app/controllers/musicians_controller.rb cargamos un objeto @hash y llamamos al método buid_markers() de la gema Gmaps4Rails. Este método necesita un objeto en este caso lo cargamos con @musicians, el cual se comunica con el modelo a través de Musician.All devolviendo todos los registros de musicos que cargamos previamente.
Luego creamos el Marcador, damos su latitud, longitud y configuramos una ventana de información que se verá así.
def index @musicians = Musician.all @hash = Gmaps4rails.build_markers(@musicians) do |musician, marker| marker.lat musician.latitude marker.lng musician.longitude marker.infowindow "<div class='box' style='width:200px;'><h4><strong>"+musician.musician_name+", "+musician.instrument.instrument_name+"</strong></h4><img src='http://img.youtube.com/vi/"+musician.youtube_video+"/mqdefault.jpg' width='111' height='90' class=''></div>" end end
Agregando el Script que dibuja el Mapa.
Ahora, inmediatamente después del html, vamos a añadir al final de app/views/musicians/index.html.erb este script:
<script type="text/javascript"> handler = Gmaps.build('Google'); handler.buildMap({ provider: {}, internal: {id: 'map'}}, function(){ markers = handler.addMarkers(<%=raw @hash.to_json %>); handler.bounds.extendWith(markers); handler.fitMapToBounds(); }); </script>
Lo que hace básicamente este script es construir el google Map.
Toda la data está contenida en el objeto @hash y google map con su método .addMarkers nos pide cargar un objeto “parseado a Json“. Para lograr esto en ruby lo hacemos asi <%=raw @hash.to_json %>
Google Maps trabaja con JSON, un standard para el intercambio de datos, con el fin de no atar su tecnología a un lenguaje de programación específico, sino que todo lo contrario, hacer que su tecnología sea compatible con cualquier lenguaje de programación con el que quieras trabajar.
Haz la prueba de imprimir por pantalla este código de ruby en la vista index:
<%=raw @hash.to_json %>
Puedes notar que obtienes una cadena de texto entre varios corchetes [{…},{…}] cierto? bueno, es la misma data que ingresamos en musician/new pero parseada en formato JSON, y si copias esta cadena más abajo en un json-parser como el que encontré, te mostrará la cadena en versión “bonita” y más legible.
[{"lat":49.2827291,"lng":-123.1207375,"infowindow":"\u003cdiv class='box' style='width:200px;'\u003e\u003ch4\u003e\u003cstrong\u003eAndres, guitarra\u003c/strong\u003e\u003c/h4\u003e\u003cimg src='http://img.youtube.com/vi/ANj8IJs38qU/mqdefault.jpg' width='111' height='90' class=''\u003e\u003c/div\u003e"},{"lat":-37.814107,"lng":144.96328,"infowindow":"\u003cdiv class='box' style='width:200px;'\u003e\u003ch4\u003e\u003cstrong\u003eEnsamble de Bronces Huevos Fritos, Brass\u003c/strong\u003e\u003c/h4\u003e\u003cimg src='http://img.youtube.com/vi/9WA-W7lI820/mqdefault.jpg' width='111' height='90' class=''\u003e\u003c/div\u003e"},{"lat":-33.4367933,"lng":-70.64107299999999,"infowindow":"\u003cdiv class='box' style='width:200px;'\u003e\u003ch4\u003e\u003cstrong\u003eAndres, piano\u003c/strong\u003e\u003c/h4\u003e\u003cimg src='http://img.youtube.com/vi/ANj8IJs38qU/mqdefault.jpg' width='111' height='90' class=''\u003e\u003c/div\u003e"},{"lat":-33.4691199,"lng":-70.641997,"infowindow":"\u003cdiv class='box' style='width:200px;'\u003e\u003ch4\u003e\u003cstrong\u003eAndrés, guitarra\u003c/strong\u003e\u003c/h4\u003e\u003cimg src='http://img.youtube.com/vi/ANj8IJs38qU/mqdefault.jpg' width='111' height='90' class=''\u003e\u003c/div\u003e"},{"lat":-33.4367933,"lng":-70.64107299999999,"infowindow":"\u003cdiv class='box' style='width:200px;'\u003e\u003ch4\u003e\u003cstrong\u003eAndrés, didgeridoo\u003c/strong\u003e\u003c/h4\u003e\u003cimg src='http://img.youtube.com/vi//mqdefault.jpg' width='111' height='90' class=''\u003e\u003c/div\u003e"},{"lat":-33.4363397,"lng":-70.6435372,"infowindow":"\u003cdiv class='box' style='width:200px;'\u003e\u003ch4\u003e\u003cstrong\u003efunky, didgeridoo\u003c/strong\u003e\u003c/h4\u003e\u003cimg src='http://img.youtube.com/vi/lMpZGAUGk8w/mqdefault.jpg' width='111' height='90' class=''\u003e\u003c/div\u003e"}]
Con estos pasos doy por finalizado el tutorial, si quieres agregar un Buscador de Músicos o de Instrumentos, revisa este Tutorial creado por Gonzalo “Haciendo un pequeño buscador en Ruby on Rails”. También para más personalizaciones del infoWindow que aparece en el, puedes revisar los ejemplos de gmaps4rails o descargar el código fuente del tutorial desde el repo que comparto con ustedes en mi cuenta de Github.
Hay bastante más que podríamos seguir integrando pero hasta aquí es la base del “how to” de este prototipo streetmusicmap y es totalmente reusable con otros conceptos. Lo entretenido es saber que en un rato (bueno o un fin de semana) puedes lograr con Ruby on Rails y unas cuantas gemas útiles, prototipos que concretan todas esas locas buenas ideas 🙂
StreetmusicMap parte 1: Combobox uno a muchos en Ruby on Rails
Hola Rubystas! para poner en práctica lo aprendido, lo mejor es crear proyectos experimentales para jugar. Aquí les presento una aplicación llamada streetmusicMap, está en su fase inicial, prototipo que comencé este fin de semana, y el cual estoy construyendo junto con mi partner de Software y creadora del blog ConciertosComentados: Melissa.
Para desarrollar esta app, comenzaré con la creación de 2 Scaffolds: Musician e Instrument. y los uniremos en el modelo a través de una relación “uno a muchos”, en donde visualmente nos ayudará un Combobox. En la Segunda Parte mostraré como esa data la integramos a un Google Map, usando la gema gmaps4Rails.
Creando la App.
Abres un Terminal y escribes:
$ rails new mapa
Acceder al proyecto desde el terminal:
$ cd mapa
Creando el Scaffold: Musician.
$ rails generate scaffold Musician latitude:float longitude:float youtube_video:string twitter:string facebook:string address:string description:string musician_name:string instrument_id:integer
(*el campo instrument_id:integer es una clave foranea del scaffold Instrument que realizaremos a continuación. y el campo latitude:float longitude:float los usaremos mas adelante en la parte 2 del streetMusicmap cuanodo integremos la gem gmaps4rails)
Ejecutamos en el terminal:
$ rake db:migrate
Creando el Scaffold: Instrument.
$ rails generate scaffold Instrument instrument_name:string
Ejecutamos en el terminal:
$ rake db:migrate
Ok, ahora tenemos 2 CRUD, Musician e Instrument (usen conceptos en inglés para crear scaffolds)
Agregar Instrumentos es simple, ya que es sólo un nombre. La parte que nos interesa es cuando agregamos un Músico, y tenemos que categorizarlo mediante un combobox cargado con instrumentos.
Modelo: Creando la relación Uno a Muchos.
Accedemos al archivo routes a través de mapa/config/routes.rb y cambiamos “welcome#index” por:
root 'musicians#index'
Al acceder por browser a nuestra vista de músicos http://locahost:3000/musicians los datos se muestran de esta manera: Nombre del Musico / ID del instrumento…pero lo que queremos ver por pantalla es el nombre del instrumento no su ID! Para lograr este proposito es que creamos la relación “uno a muchos” en el modelo:
En app/models/musician.rb escribe:
class Musician < ActiveRecord::Base belongs_to :instrument end
Y en app/models/instrument.rb escribes:
class Instrument < ActiveRecord::Base has_many :musicians end
la relación entre Músico e Instrumento en nuestro ejercicio específicamente se lee así:
“un Músico pertenece_a una categoría” (belongs_to)
y “Una categoría tiene_muchos Musicos”. (has_many)
La Vista: Cambiando instrument_id.
en app/views/ musicians/ index.html.erb buscas:
<%= musician.instrument_id %>
y lo reemplazas por:
<%= musician.instrument.instrument_name %>
Refrescas el browser y verás por pantalla ahora el Nombre del instrumento en lugar de su ID..mucho mejor!
El Controller: Modificando el método new
Al mostrar la view /musicians/new tenemos que agregar un nuevo objeto @instruments, el cual recibirá todos los registros que el Modelo le devuelva y esos datos lo vamos a cargar en un combobox.
En app/controllers/musicians_controller.rb busca:
def new @musician = Musician.new end
y lo reemplazas por:
def new @musician = Musician.new @instruments = Instrument.all end
Ahora en la vista parcial app/views/musicians/_form.html.erb busca:
<%= f.number_field :instrument_id %>
y reemplázalo por este helper: (ésta línea dibuja el combobox de instrumentos por pantalla)
<%= collection_select(:musician, :instrument_id, @instruments, :id, :instrument_name, prompt: true) %>
Desde tu navegador ingresa a:
http://localhost:3000/musician/new
Excelente! 🙂 Ahora vemos un Combobox para categorizar a nuestros musicos. Más info sobre este Helper collection_select aquí!
Seguramente si accedes a la view “edit” verás un error, eso es porque tenemos que agregar un objeto @instruments en el método “edit” del controller musician ya que también al editar un registro de músico, necesitamos ver el combobox cargado pero posicionando en primer item el instrumento que le pertenece a este músico.
En app/controllers/musicians_controller.rb busca:
def edit end
y lo reemplazas por:
def edit @musician = Musician.find(params[:id]) @instruments = Instrument.all end
Ya estamos casi terminando nuestra primera parte de la aplicación, sólo un detalle más…
En app/views/musicians/show.html.erb busca:
<%= @musician.instrument_id %>
y lo reemplazas por:
<%= @musician.instrument.instrument_name %>
Y ya tienes una aplicación uniendo 2 scaffolds y cargando un combobox en la Vista.
pd: Se viene luego la parte 2: Ahora te recomiendo ir por una buena taza de café y luego revisa el tutorial parte 2: Integración con google maps y la gema Gmaps4Rails.
3 plataformas para almacenar rails en la nube
Existen diversas plataformas para almacenar aplicaciones web como Ruby on Rails en la nube. Pero hay 3 que sobresalen, así que comparemoslas.
- Elastic Beanstalk
- Heroku
- EngineYard
Para ir al grano, Elastic Beanstalk de Amazon gana, pero todo dependerá de tu situación.
Características que todas estas plataformas tienen en común.
- Implementación desde la línea de comando con Git
- Soporte completo para aplicaciones de Ruby/Rails
- Gemas instaladas y actualizadas automáticamente en cada Push
- Facilidades para manejar migraciones (db:migrate)
- Soporte a base de datos integrada (no necesita instalación por separado)
Ninguna de estas características viene en Elastic Beanstalk cuando es iniciado por primera vez. Si no más bien, viene mucho más adelante, así que puedes ir reconsiderando esto si es que lo has ignorado.
Heroku
Pros:
Es muy fácil comenzar con Heroku, solo debes instalar el “toolkit” y seguir este recetario.
La documentación es simple y directa.
Heroku es la opción más barata para un sitio de bajo tráfico, así que puedes comenzar un sitio con una base de datos básica totalmente gratis. Aunque será un poco lento si es que tienes un montón de tráfico.
Tiene un plan gratuito y no necesitas tener una tarjeta de crédito para usarlo, pero si para instalar plugins o subir el plan al modo pagado.
Los respaldos son manejados automáticamente con pgbackups.
Provee un montón de extras, haciendo más fácil integrar sistemas como NewRelic para monitoreo y SendGrid o Mandrill para emails. La integración de la base de datos es simple con el soporte Postgres pero se pueden ocupar otras.
Tiene plan gratuito.
CONS:
Una vez que haz añadido poder y manejas más tráfico, el precio del plan sube rápidamente.
Necesitas extraer manualmente tu aplicación añadiendo “dynos”. un concepto un poco vago que utiliza Heroku .
El soporte al cliente es algo pobre, pero no he tenido que utilizarlo muy frecuentemente.
No puedes ingresar en tu servido vía SSH
Nosotros en En1mes usamos Heroku para todo nuestro testeo de aplicaciones y para pequeños proyectos que desean crecer.
Engine Yard
PROS:
El escalamiento (ampliación de recursos disponibles para atender a más usuario) ocurre automáticamente, así que puedes manejarlo hasta el máximo (aunque esto pueda guiar a un cobro gigantesco).
Puedes usar SSH en el servidor.
Los respaldos son manejados automáticamente.
Provee un montón de extras, haciendo más fácil integrar sistemas como NewRelic para monitoreo y SendGrid para emails.
La integración de base de datos es simple con Postgres y hay soporte MySQL.
El soporte al cliente es excelente.
CONS
Es un poco más de trabajo para implementar que Heroku y después de la primera publicación, demora un poco en actualizarse.
Es caro, es fácil pagar cerca de $60.000 pesos en un solo mes, por un servidor con poco tráfico en el sitio.
EngineYard aplica un 20% de recargo en todos los precios Amazon, así como el uso de Amazon para almacenamiento, direcciones IPs y respaldos. Esto siempre resulta un poco más caro.
Personalmente recomendaría EngineYard para la producción de productos donde el dinero no es problema. Ni tampoco donde el soporte y la interacción mínima con ajustes es requerida.
Elastic Beanstalk
PROS
Nuevos usuarios pueden usar Elastic Beanstalk y algunos sub-servicios totalmente gratis, por el tiempo aproximado de 1 año. (Esto le hace competir directamente con Heroku)
Un ejemplo de sitio con bajo tráfico en Elastic Beanstalk después del periodo de prueba está a $20.500 pesos por mes. Para correr el mismo sitio en EngineYard puede costar al menos $ 50.000 pesos por mes.
Las incrustaciones ocurren automáticamente, así que puedes manejarlo hasta el máximo (aunque esto pueda guiar a una cuenta sorprendentemente grande).
Puedes usar SSH en el servidor y cambiar ciertas cosas.
Los respaldos son manejados automáticamente.
CONS
Es un poco más de trabajo para ajustar y utilizar por primera vez que heroku y hasta que EngineYard (el kit de herramientas necesita una instalación manual.
No puedes hacerlo como una gema, pero esto solo toma unos pocos minutos.
Para usar la base de datos y tener la misma facilidad en Heroku y EngineYard, necesitarás usar el servicio Amazons RDS (el cual provee un MySQL, Oracle o SQL servidor de base de datos).
No hay plugins así que es un poco más complejo de integrar con herramientas de monitoreo NewRelic (aunque esto es gratis para AWS users) y SendGrid.
Elastic Beanstalk en sí mismo, es gratis. Pero debes pagar por el ancho de banda, almacenamiento, base de datos, respaldos, etc.
No tienes mucho feedback por parte del servidor cuando lo ejecutas así como Heroku y EngineYard.
Elastic Beanstalk es lo que yo recomendaría como hosting para tener un balance entre servicio y precio. Incluso puedes comenzar un proyecto pequeño de la manera correcta debido a su almacenamiento gratis. Existen más contras para Elastic Beanstalks, pero siento que son compensados por el precio en muchas situaciones.
Advertencia: A medida que tu aplicación empiece a crecer sufrirá frecuentemente de bots y otros tipos de ataque que se conectan y capturan datos de tu sitio o simplemente utilizan recursos de tu sitio, si ocupas plataformas que escalan automáticamente siempre serás capaz de mostrarles resultados a tus usuarios pero tus costos podrían crecer exponencialmente, y fácilmente multiplicarse por cien o incluso por mil.