Cloudinary images aren't displaying on live site - ruby-on-rails

Pretty new to Rails, but I'm having an issue getting images to display on a live site. The images are uploaded by the user as part of creating a post, but I'm running into two issues:
The media library is not updating when an image is uploaded
On localhost the upload works fine and is displayed, however on the live site the images are not being displayed. The page loads fine but the Cloudinary image src generated doesn't point anywhere
Example:
<img class="main-post-image" src="https://res.cloudinary.com/hw2ugvhic/image/upload/vfvhamrbx0jz8rj6y17c2vy4m2gp">
New post view:
<div class="text-center mt-3">
<h1>New post</h1>
</div>
<div class = "main-form-container">
<div class= "post-form-container">
<div data-controller="multi-upload">
<%= simple_form_for [#country, #area, #post] do |f| %>
<%= f.input :title %>
<%= f.input :summary %>
<%= f.input :description, as: :rich_text_area %>
<%= f.input :category , collection: %w(bar restaurant activity nature memory) %>
<%= f.input :main_image, as: :file, label: "square image only"%>
<%= f.file_field :images, multiple: true, data: {action: "multi-upload#addFile"} %>
<div data-multi-upload-target="files"></div>
<div class = "d-flex justify-content-center">
<%= f.button :submit, class: "green-button mt-3"%>
</div>
<div class = "text-link text-center mt-2">
<%= link_to "Go back", country_area_path(#country, #area) %>
</div>
<% end %>
</div>
</div>
</div>
Posts controller:
class PostsController < ApplicationController
def new
#country = Country.find(params[:country_id])
#area = Area.find(params[:area_id])
#post = Post.new
end
def create
#country = Country.find(params[:country_id])
#area = Area.find(params[:area_id])
#post = Post.new(post_params)
#post.user = current_user
#post.area = #area
if #post.save
redirect_to country_area_path(#country, #area)
else
render :new
end
end
def show
#country = Country.find(params[:country_id])
#area = Area.find(params[:area_id])
#post = Post.find(params[:id])
end
def edit
#post = Post.find(params[:id])
#area = Area.find(params[:area_id])
#country = Country.find(params[:country_id])
end
def update
#area = Area.find(params[:area_id])
#country = Country.find(params[:country_id])
#post = Post.find(params[:id])
#post.update(post_params)
redirect_to country_area_post_path(#country, #area, #post)
end
private
def post_params
params.require(:post).permit(:title, :summary, :description, :category, :area_id, :main_image, images: [])
end
end
Post model:
class Post < ApplicationRecord
belongs_to :user
belongs_to :area
has_one_attached :main_image, dependent: :destroy
has_many_attached :images, dependent: :destroy
has_rich_text :description
validates :title, :summary, :description, :category, :main_image, presence: true
end
Area show view page (where the posts can be viewed)
<nav aria-label="breadcrumb" class="mt-2 pl-2">
<ol class="breadcrumb">
<li class="breadcrumb-item"><%= link_to "Home", root_path %></li>
<li class="breadcrumb-item"><%= link_to #country.name, country_path(#country) %></li>
<li class="breadcrumb-item active" aria-current="page"><%= #area.name %></li>
</ol>
</nav>
<% unless #posts.empty?%>
<div class = main-posts-div>
<div>
<%= "Welcome to #{#area.name}, #{#country.name}"%>
</div>
<%= link_to "New post", new_country_area_post_path(#country, #area), class: "green-button mt-3"%>
<div>
<div class="area-main-div">
<% #posts.each do |post| %>
<%= link_to country_area_post_path(#country, #area, post) do %>
<div class= "post-card">
<div>
<% if post.main_image.nil? %>
<%= image_tag("https://picsum.photos/300/300") %>
<% else %>
<%= cl_image_tag(post.main_image.key, class:"main-post-image") %>
<% end %>
</div>
<div class = "lower-post-card">
<div>
<%= post.title %>
</div>
<div>
<em><%= post.category %></em>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
</div>
<% else %>
<div class="main-posts-div-blank">
<div>
<%= "Welcome to #{#area.name}, #{#country.name}. #{#area.name} is yet to be explored, please document your experience"%><br>
</div>
<%= link_to "New post", new_country_area_post_path(#country, #area), class: "green-button mt-3"%>
</div>
<% end %>
Areas controller
class AreasController < ApplicationController
def new
#area = Area.new
end
def create
#country = Country.find(params[:country_id])
#area = Area.new(area_params)
#area.country = #country
#area.save
redirect_to country_path(#country)
end
def show
#area = Area.find(params[:id])
#country = Country.find(params[:country_id])
#post = Post.new
#posts = Post.where(area_id: #area)
end
private
def area_params
params.require(:area).permit(:name, :country_id)
end
end
Steps already taken
Added Cloudinary to Heroku
Created a dotenv file with the cloudinary key
added cloudinary gem
Updated the following:
storage.yml
cloudinary:
service: Cloudinary
folder: <%= Rails.env %>
development.rb
config.active_storage.service = :cloudinary
What can I try next?

I think the only thing that might be missing is that active storage does not store the folder as part of the key e.g. post.main_image.key would be a random string but is missing folderName/<random-string> which you defined in the storage.yml file.
I believe you just need to include the folder name in the cl_image_tag(post.main_image.key, class:"main-post-image") should be cl_image_tag("folderName/"+post.main_image.key, class:"main-post-image")
There probably is a way to pass that dynamically.

Related

Trying to create comments inside posts - rails

I'm traying to create a social media with posts and comments inside the posts.
I'm trying to link the comments to the posts but I'm not going well. I dont know if the bug is from the controllers or the views. That`s what I have:
Comment model:
class Comment < ApplicationRecord
belongs_to :user
belongs_to :post
end
post model:
class Post < ApplicationRecord
belongs_to :user
has_many :comments
end
routes:
resources :posts do
member do
resources :comments
end
end
posts controller (the idea is to show the comment form and show inside the posts, and make a kind of feed, like facebook, instagram.. ):
class PostsController < ApplicationController
def index
#posts = Post.includes(:user).order(updated_at: :desc)
#comment = Comment.new
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.user = current_user
if #post.save
redirect_to request.referrer
# redirect_to feed_users_path
else
render :new
end
end
private
def post_params
params.require(:post).permit(:content, :user)
end
end
comments controller:
class CommentsController < ApplicationController
def create
#comment = Comment.new(comment_params)
#comment.user = current_user
#comment.post = #post
if #comment.save
redirect_to request.referrer
end
end
private
def comment_params
params.require(:comment).permit(:content, :post, :user)
end
end
this is the post index:
<% #posts.each do |post| %>
<div class="row" id="post-<%= post.id %>">
<div class="col-12 post-container">
<!-- header -->
<div class="post-header d-flex justify-content-start">
<%= link_to user_path(post.user) do %>
<h5><%= post.user.first_name %> <%= post.user.last_name %></h5>
<% end %>
<p>
<%= link_to user_path(post.user) do %>
#<%= post.user.first_name %>
<% end %>
<span><%= distance_of_time_in_words(Time.now, post.created_at) %></span> ago
</p>
</div>
<!-- content -->
<div class="post-content">
<div class="post-text">
<h4><%= post.content %></h4>
</div>
</div>
<hr>
<div class="form--input">
<%= simple_form_for([#post.comment], remote: true) do |f| %>
<div class="form--input">
<%= f.input :content, input_html: { class: "form-txt py-3" }, placeholder: "What do you want to comment?", label: false %>
</div>
<div class="form--input_elements d-flex justify-content-between mx-4">
<div class="form--input_submit">
<%= f.submit "Post Comment", class: "btn btn-flat", id: "post-submit", role: "status", remote: true %>
</div>
</div>
<% end %>
</div>
</div>
</div>
<% end %>
You have a problem in the routes file, it should be like this :
resources :posts do
resources :comments
end

rails 6 form validation errors even when criteria is met

I am trying to add form validation to a simple blog post form. Currently I am testing for presence of title and description and if I submit an empty form it gives me the errors, but if I fill out the form it still gives me the errors. When I use byebug in my create action for the post_controller it shows the contents of the title and description that I enter but says permitted false.
Here is the form partial:
<%= form_with(model: post, local: true) do |f| %>
<% if post.errors.any? %>
<div class="row center-align">
<div class="card-panel alert alert-danger">
<span class="white-text">
<strong><%= pluralize(post.errors.count, "error") %></strong>
occured:
<ul>
<% post.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</span>
</div>
</div>
<% end %>
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :description %>
<%= f.text_area :description, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :header_image %>
<%= f.file_field :header_image %>
</div>
<div class="mt-1">
<% if post.header_image.present? %>
<small>Current Image</small>
<%= image_tag(post.header_image, width: '100%') %>
<% end %>
</div>
<div class="actions">
<%= f.submit class: 'btn btn-primary mt-1 form-control' %>
</div>
<% end %>
Here is the post_controller:
module Authors
class PostsController < AuthorsController
before_action :set_post, only: [:edit, :update, :destroy]
# GET /posts
def index
#posts = current_author.posts
end
# GET /posts/new
def new
#post = current_author.posts.build
end
# GET /posts/1/edit
def edit
#element = #post.elements.build
end
# POST /posts
def create
#post = current_author.posts.build
if #post.save
redirect_to edit_post_path(#post), notice: 'Post was successfully created.'
else
render :new
end
end
# PATCH/PUT /posts/1
def update
if #post.update(post_params)
redirect_to edit_post_path(#post), notice: 'Post was successfully updated.'
else
render :edit
end
end
# DELETE /posts/1
def destroy
#post.destroy
redirect_to posts_url, notice: 'Post was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = current_author.posts.find(params[:id])
end
# Only allow a list of trusted parameters through.
def post_params
params.require(:post).permit(:title, :description, :header_image)
end
end
end
And her is the post.rb:
class Post < ApplicationRecord
belongs_to :author
has_many :elements
has_one_attached :header_image
validates :title, :description, presence: true
end
The post form was working fine until I tried adding the validations.
When I add buy but and test it I get the following when I run params:
#<ActionController::Parameters {"authenticity_token"=>"1hQyn6kWCiCwAaeaUa1PD9q76D29RF-56LKof1uC64auGtNvA2VCZ-mDLdY7EjCYP9zWpLLvfkgkE33AUZP7Ng", "post"=>{"title"=>"Testing", "description"=>"test"}, "commit"=>"Create Post", "controller"=>"authors/posts", "action"=>"create"} permitted: false>
(byebug)
In the create method, you're not instantiating the Post object with post_params. So, #post.title and #post.description are nil causing the validations to fail.
#post = current_author.posts.build(post_params)

add a associated value in ruby on rails from independent page

im beginner of ruby on rails. i have brand - products list.
Brand,
class Brand < ApplicationRecord
has_many :products, dependent: :destroy
validates :title, presence: true,
length: { minimum: 2 }
end
Product,
class Product < ApplicationRecord
belongs_to :brand
end
products.controller
class ProductsController < ApplicationController
skip_before_action :verify_authenticity_token
def edit
#product = Product.find(params[:id])
end
def new
#product = Product.new
end
def update
#brand = Brand.find(params[:brand_id])
#product = Product.find(params[:id])
#product.update(product_params)
redirect_to brand_path(#brand)
end
def create
#brand = Brand.find(params[:brand_id])
#product = #brand.products.create(product_params)
redirect_to brand_path(#brand)
end
def destroy
#brand = Brand.find(params[:brand_id])
#product = #brand.products.find(params[:id])
#product.destroy
redirect_to brand_path(#brand)
end
def update
#brand = Brand.find(params[:brand_id])
#product = #brand.products.find(params[:id])
#product.destroy
end
helper_method :update
private
def product_params
params.require(:product).permit(:name)
end
end
the new.html.erb,
<h1> Add a new product </h1>
<%= form_with model: #brand, local: true do |form| %>
<p>
<%= form.label :title,"Product name" %><br>
<%= form.text_field :name %>
</p>
<p>
<%= form.label :title,"Select a Brand" %><br>
<%= form.collection_select(:brand, Brand.all, :id, :title) { #brand = Brand.find(params[:brand_id]) } %>
</p>
<p>
<%= form.submit "Save Product", :onclick => "create" %>
</p>
<% end %>
routes.rb
Rails.application.routes.draw do
get 'welcome/index'
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
resources :brands do
resources :products
end
root 'welcome#index'
end
when i cliked the button i get error,
No route matches [POST] "/brands/%23%3CBrand::ActiveRecord_Relation:0x00007f5e30d87490%3E/products/new"
Rails.root: /home/berkay/e-ticaret
SO, how can i save this product?
change that one
<%= form_with model: #brand, local: true do |form| %>
to
<%= form_with(model: #product, url: [#brand, #product]) %>
Also add
#brand = Brand.find(a_brand_id)
inside your new method of ProductsController class. So, rails is going to know which brand is parent of that product.
UPDATE
I've created a dummy project which is going to work as you expected.
products/_form.html.erb partial for product
<%= form_with(model: product, local: true) do |form| %>
<% if product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% product.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :title %>
<%= form.text_field :title %>
</div>
<div class="field">
<%= form.label :title, "Select a Brand" %><br>
<%= form.collection_select(:brand_id, Brand.all, :id, :title, {selected: #brand.id}) %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
routes.rb
Rails.application.routes.draw do
resources :products
resources :brands
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
products_controller.rb
class ProductsController < ApplicationController
# GET /products/new
def new
if params[:brand_id]
#brand = Brand.find(params[:brand_id])
end
#product = Product.new
end
def edit
#brand = #product.brand
end
...
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:title, :brand_id)
end
end
I've also added a hotlink to create a product for a given brand
brands/show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Title:</strong>
<%= #brand.title %>
</p>
<%= link_to 'Edit', edit_brand_path(#brand) %> |
<%= link_to 'Back', brands_path %> |
<%= link_to 'Create Products', new_product_path(brand_id: #brand.id) %>
When using nested routes you would have to write
form_with model: [#brand, #product]
it will use the array to compose the path and the last item will be actually edited.
Your new action should best be changed as follows:
def new
#brand = Brand.find(params[:brand_id)
#product = #brand.products.build
end

has_many join form with collection checkboxes not saving more than one checkbox value

I am working on a form for a editorial calendar app. I have two things going out that are pretty similar and not working.
Working with 3 models: Platforms, Posts and Calendars. They are join tables. Platform <=> Post, Post <=> Calendars
Post/new & Post/edit form:
<div class="container">
<div class="form-field">
<%= form_for #post do |f| %>
<%= f.label :title %>
<%= f.text_field :title, required: true %> <br>
Title is required.
</div>
<div class="form-field">
<%= f.label :content%>
<%= f.text_area :content%>
</div>
<div class="form-field">
<%= f.label :link %>
<%= f.text_field :link %>
</div>
<div class="file-field">
<%= f.label :picture%>
<%= f.file_field :picture, id: :post_picture%>
</div>
<div class="file-field">
<%= f.label :finalized %>
<%= f.radio_button :finalized , true%>
<%= f.label :finalized, "Yes" %>
<%= f.radio_button :finalized, false %>
<%= f.label :finalized, "No" %>
</div>
<%= f.hidden_field :user_id %> <br>
<div class="form-field">
<%= f.fields_for :platform_attributes do |platform| %>
<%= platform.label :platform, "Social Platforms"%>
<%= platform.collection_check_boxes :platform_ids, Platform.all, :id, :name %> <br> <br>
</div>
<div>
<h4> Or Create a new platform: </h4>
<%= platform.label :platform, 'New Platform'%>
<%= platform.text_field :name%> <br> <br>
</div>
<% end %>
<%= f.submit%>
<% end %>
</div>
My post controller is handling the checkboxes issue, and the "schedule post" issue. It will only allow me to schedule for one calendar, and it does not save the updates and add additional calendars.
Posts Controller:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :schedule_post, :destroy]
def new
#posts = current_user.posts.select {|p| p.persisted?}
#post = current_user.posts.build
#platforms = Platform.all
end
def edit
#calendars = current_user.calendars
#platforms = Platform.all
end
def create
#post = current_user.posts.build(post_params)
if #post.save
redirect_to post_path(#post)
else
redirect_to new_post_path
end
end
def update
#post.update(post_params)
if #post.save
redirect_to post_path(#post), notice: 'Your post has been updated.'
else
redirect_to edit_post_path(#post)
end
end
def schedule_post
#calendar_post = CalendarPost.new(calendar_post_params)
if #calendar_post.save
binding.pry
redirect_to post_path(#post)
else
render 'show'
end
end
private
def set_post
#post = Post.find(params[:id])
end
def set_calendars
#calendars = current_user.calendars
end
def post_params
params.require(:post).permit(:title, :content, :link, :finalized, :picture, :user_id, :platform_attributes => [:platform_ids, :name])
end
def calendar_post_params
params.require(:calendar_post).permit(:post_id, :calendar_id, :date, :time)
end
end
I want the user to be able to add a post to multiple platforms and multiple calendars because of the versatility of what someone may need.
I also have my setter in my Post model.
class Post < ApplicationRecord
has_many :calendar_posts
has_many :calendars, through: :calendar_posts
has_many :platform_posts
has_many :platforms, through: :platform_posts
belongs_to :user
def platform_attributes=(platform_attributes)
if platform_attributes['platform_ids']
platform_attributes.platform_ids.each do |id|
platform = Platform.find(id: id)
self.platforms << platform
end
end
if platform_attributes['name'] != ""
platform = Platform.find_or_create_by(name: platform_attributes['name'])
self.platforms << platform
end
end
thoughts? why are they not saving to more than one calendar or more than one platform if they choose to have more than one?
Here is the updated code... and more of what I know about these changes and what is happening.
My submit button is not working for some odd reason on my form, so I'm trying to get the params submitted but it won't even route to give me params even if I raise them, nothing is happening.
On the form you can choose checkboxes or add in a platform. If you add in a platform it creates that one but it does not also save the other ones you selected. If you go to edit the post, and click submit with changes, no page loads at all and nothing is happening in log. It's just idle.
<%= f.fields_for :platform_attributes do |platform| %>
assumes you are creating one platform... it says "these are the fields for this platform"
but platform_ids is intended to be a selection of a set of platforms... and probably should be outside of the fields_for section (which should only surround the name field).
try something like the following:
<div class="form-field">
<%= f.label :platform_ids, "Social Platforms"%>
<%= f.collection_check_boxes :platform_ids, Platform.all, :id, :name %> <br> <br>
</div>
<div>
<%= f.fields_for :platform_attributes do |platform| %>
<h4> Or Create a new platform: </h4>
<%= platform.label :name, 'New Platform'%>
<%= platform.text_field :name%> <br> <br>
<% end %>
<%# end fields_for %>
</div>
Also you'll need to update permit/require appropriately eg
def post_params
params.require(:post).permit(:title, :content, :link, :finalized, :picture, :user_id, :platform_ids, :platform_attributes => [:name])
end
Note: not tested - bugs are left as an exercise for the reader ;)

while Form sumbitting extra blank item

When I submit an answer form, the first item is getting the only empty string, how I can fix it and guide me.
Extra item picture:
question model
class Question < ApplicationRecord
has_many :answers, dependent: :destroy
end
answer model
class Answer < ApplicationRecord
belongs_to :question
end
answer controller
class AnswersController < ApplicationController
def create
#question = Question.find(params[:question_id])
#answer = #question.answers.create(params[:answer].permit(:body))
redirect_to question_path(#question)
end
def destroy
#question = Question.find(params[:question_id])
#answer = #question.answers.find(params[:id])
#answer.destroy
redirect_to question_path(#question)
end
end
answer form
<%= form_for([#question,#question.answers.build]) do |f| %>
<div class="row">
<div class="input-field col s12 m9">
<%= f.text_area :body ,:id=>"ans_form" %>
<label for="first_name"style="text-indent:15px;line-height:15px">Create Possible Answer</label>
</div>
<div class="input-field col s12 m3">
<%= button_tag(type: 'submit', class: "col s12 btn waves-effect accent-4") do %>
Create Answer
<% end %>
</div>
</div>
<% end %>
in my view (show page )
<%= #question.answers.each do |answer| %>
<%= answer.body %>
<%= link_to 'delete',[answer.question, answer], method: :delete %>
<% end %>

Resources