Redirect the editing of nested content - ruby-on-rails

Problem resolve
When I want to edit an existing section an error appears:
"Couldn't find Category with'id' ="
And my page is redirected to "http://localhost:3000/sections/1" when it should be redirected to "http://localhost:3000/categories/3/sections/1/".
sections_controller.rb
class SectionsController < ApplicationController
before_action :find_the_category
def index
#sections = #category.sections
end
def show
#section = #category.sections.find(params[:id])
end
def new
#section = Section.new
end
def edit
#section = #category.sections.find(params[:id])
end
def create
#section = #category.section.create(section_params)
flash[:success] = "Section ajouté avec succés"
if #section.save
redirect_to category_section_path(#category, #section)
end
end
def update
flash[:success] = "Section modifié avec succés"
#section = #category.sections.find(params[:id])
#section.update(section_params)
redirect_to category_section_path(#category, #section)
end
def destroy
flash[:danger] = "Section supprimé"
#section = Section.find(params[:id])
#section.destroy
redirect_to category_sections_path
end
private
def find_the_category
#category = Category.find(params[:category_id])
end
def section_params
params.require(:section).permit(:title, :content)
end
end
routes.rb
Rails.application.routes.draw do
resources :categories do
resources :sections
end
end
section#_form.html.erb
<%= bootstrap_form_for([#category, #section]) do |f| %>
<% if #section.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#section.errors.count, "error") %> prohibited this reponse from being saved:</h2>
<ul>
<% #section.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :Titre %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :Description %><br>
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
category.rb
class Category < ActiveRecord::Base
# une catégorie peut avoir plusieurs questions relations has-many
has_many :questions
has_many :sections
end
section.rb
class Section < ApplicationRecord
belongs_to :category
end

Check your form url in browser, i think it wrong.
You don't provide any category to bootstrap_form_for helper, so it may generate wrong link.
Your form template must be smth like this:
bootstrap_form_for([#category, #section])

Related

Cloudinary images aren't displaying on live site

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.

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

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

Can't render checkboxes in a Rails 4 many_to_many association?

I have a many_to_many association between Articles and Categories, using has_and_belongs_to_many in a Rails 4 app:
Here are the corresponding migration and classes:
class CategoriesArticles < ActiveRecord::Migration
def change
create_table :articles_categories, id: false do |t|
t.belongs_to :category, index: true
t.belongs_to :article, index: true
end
add_index :articles_categories, [:category_id, :article_id]
end
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :articles
end
class Article < ActiveRecord::Base
has_and_belongs_to_many :categories
end
When a user creates a new article, I simply want to give him or her the option to select categories that he/she wants to associate with the new article. I want the user to be able to select these categories with checkboxes.
Here's the ArticlesController:
class ArticlesController < ApplicationController
before_action :set_article, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, only: [:new, :create, :edit, :destroy, :update]
before_action :verify_own_article, only: [:destroy]
respond_to :html
...
def new
#categories = Category.all
#article = Article.new
respond_with(#article)
end
def create
# Creates article object with current_user_id, initial_comment, and URL
#article = current_user.articles.build(article_params)
# Uses Pismo (gem) to grab title, content, photo of URL
#article.populate_url_fields
if #article.save
flash[:success] = "Article created!"
# Might need to change the location of this redirect
redirect_to root_url
else
flash[:notice] = "Invalid article."
redirect_to new_article_path
end
end
def update
#article.update(article_params)
flash[:notice] = "Article successfully updated."
respond_with(#article)
end
private
def set_article
#article = Article.find(params[:id])
end
def article_params
params.require(:article).permit(:url, :title, :datetime, :content, :photo, :initial_comment)
end
# Ensure that a signed in user can only delete articles that they have posted
def verify_own_article
#article = current_user.articles.find_by_id(params[:id])
end
end
Here's the article new.html.erb view:
<h1>New article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>
... and the form partial:
<%= form_for(#article) do |f| %>
<% if #article.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#article.errors.count, "error") %> prohibited this article from being saved:</h2>
<ul>
<% #article.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :url %><br>
<%= f.text_field :url %>
</div>
<div class="field">
<%= f.label :initial_comment %><br>
<%= f.text_field :initial_comment %>
</div>
<% #categories.each do |t| %>
<div class="field">
<%= f.label t.name %>
<%= f.check_box "categories[#{t.id}]" %>
<br />
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
However, this is erroring for me, specifically the lines:
<% #categories.each do |t| %>
<div class="field">
<%= f.label t.name %>
<%= f.check_box "categories[#{t.id}]" %>
<br />
</div>
<% end %>
Specifically, it's telling me:
undefined method 'categories[1]' for #<Article:0x007f401193d520> when I try to render the New Article page. How do I fix this? Thanks.
It is better to use Rails collection_check_boxes helper instead of trying to create those checkboxes by hand. This helper already creates all the parameter / markup stuff you need in order to add or exclude items of a HABTM relation, all under the hood. So you might change you view to include the following:
<%= f.collection_check_boxes :categories_ids, #categories, :id, :name %>
Don't forget to add this in your strong parameters declaration (since you'll have to receive the selected categories ids and bind them to your Article model):
params.require(:article).permit(
:url, :title, :datetime, :content,
:photo, :initial_comment, categories_ids: []
)
For further customizations (html styling or structure for each checkbox), please refer to the complete documentation
I hope it helps :)

partial form for nested models in rails 3

I have two models pages and author, here is the code of model pages:
edit -1
now my models are as follows:
class Page < ActiveRecord::Base
validates :title, :presence => true
belongs_to :author
end
author model:
class Author < ActiveRecord::Base
has_many :pages
end
and my form is as follows:
<%= form_for(#page) do |f| %>
<% if #page.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#page.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #page.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.fields_for :author do |fields| %>
<%= f.label :author %><br />
<%= fields.text_field :author %>
<% end %>
</p>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :reference %><br />
<%= f.select(:reference,[['google',1],['yahoo',2],['MSN',3],['Ask',4]]) %>
</p>
<%= f.submit "Submit" %>
<% end %>
and controller :
class PagesController < ApplicationController
def index
#total = Page.count
#pages = Page.find(:all)
end
def show
#page = Page.find(params[:id])
end
def new
#page = Page.new
end
def create
#page = Page.new(params[:page])
if #page.save
redirect_to pages_path, :notice => "The data has been saved!"
else
render "new"
end
end
def edit
#page = Page.find(params[:id])
end
def update
#page = Page.find(params[:id])
if #page.update_attributes(params[:page])
redirect_to pages_path, :notice => "Your post has been updated!"
else
render "edit"
end
end
def destroy
#page = Page.find(params[:id])
#page.destroy
redirect_to pages_path, :notice => "Your page has been deleted!"
end
end
Now when i am submitting the form it is giving me this error:
ActiveRecord::AssociationTypeMismatch in PagesController#create
Author(#40328004) expected, got ActiveSupport::HashWithIndifferentAccess(#32291496)
Rails.root: C:/rorapp
Application Trace | Framework Trace | Full Trace
app/controllers/pages_controller.rb:19:in `new'
app/controllers/pages_controller.rb:19:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"hzBlXsdUjEDDCLp036R8bJBwep6BdATSvJPNwt0M8Dg=",
"page"=>{"title"=>"",
"body"=>"",
"author"=>{"author"=>""},
"email"=>"",
"reference"=>"1"},
"commit"=>"Submit"}
Show session dump
Show env dump
Response
Headers:
None
and one more problem if I add accepts_nested_attributes_for :author to my Page model, then the field is not displayed at all. I really want to accomplish this.. any help?
Apparently this doesn't work in reverse with the association. I'm sorry for the mistake. You could do the following, but then your pages controller is acting on the author, which isn't really appropriate. You could make an author controller though, and include fields_for :pages, to have the author and the first page created at the same time.
class PagesController < ApplicationController
def new
#author = Author.new
#page = #author.pages.new
end
def create
#author = Author.create(params[:author])
end
end
class Author < ActiveRecord::Base
has_many :pages
accepts_nested_attributes_for :pages
end
class Page < ActiveRecord::Base
belongs_to :author
end
<%= form_for(#author, :url => pages_url) do |f| %>
<%= f.text_field :author %>
<%= f.fields_for :pages do |fields| %>
<%= fields.text_area :body %>
<% end %>
<% end %>

Resources