Issue with a nested form_for's parameter - ruby-on-rails

I'm creating a website on which people can read mangas, thanks to three scaffolds : one for the manga itself, one for its chapters and a last one for the chapter's pages. In my routes.rb file, I nested the pages inside the chapter resources, which I nested inside the manga's, so my routes look like the following:
resources :mangas do
resources :chapters do
resources :pejis #Rails doesn't like the "scan" word
end
end
I can create a manga without troubles, but for an unknown reason, I can't manage to make the form appear:
views/chapters/_form.html.erb
<%= form_for(chapter) do |f| %>
<div class="field">
<%= f.label :titre %>
<%= f.text_field :titre %>
</div>
<div class="field">
<%= f.label :apercu %>
<%= f.file_field :apercu %>
</div>
<div class="field">
<!-- Allows me to upload the chapter's pages in the same time -->
<label for="images[]">Multi Upload</label>
<%= file_field_tag 'images[]', type: :file, multiple: true %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
The form_for parameter is as it was when created by the scaffold command. However, obviously, it doesn't work since I nested the resources inside the manga scaffold. I tried a few things, until new_manga_chapter_path allowed me to see the form. However, when submitting it, I'm getting the following error:
No route matches [POST] "/mangas/1/chapters/new". I'm not even sure if this is normal or strange.
I'm pretty sure I shouldn't put "new_manga_chapter_path" as parameter for the form_for but I have no idea what to put instead.
Just in case, here is the chapter controller:
class ChaptersController < ApplicationController
before_action :set_chapter, only: [:show, :edit, :update, :destroy]
def index
#chapters = Chapter.all
end
def show
end
def new
#chapter = Chapter.new
end
def edit
end
def create
#chapter = Chapter.new(chapter_params)
if #chapter.save
(params[:images] || []).each_with_index do |image, index|
#chapter.pejis.create(image: image, scan_number: index + 1)
end
redirect_to #chapter, notice: 'Chapter was successfully created.'
else
render :new
end
end
def update
if #chapter.update(chapter_params)
(params[:images] || []).each_with_index do |image, index|
#chapter.pejis.create(image: image, scan_number: index + 1)
end
redirect_to #chapter, notice: 'Chapter was successfully updated.'
else
render :edit
end
end
def destroy
#chapter.destroy
redirect_to chapters_url, notice: 'Chapter was successfully destroyed.'
end
private
def set_chapter
#chapter = Chapter.friendly.find(params[:id])
end
def chapter_params
params.require(:chapter).permit(:titre, :apercu)
end
end
Don't hesitate if you want to see something else
Thank you in advance

Try this:
# don't replace the [] by ()
<%= form_for [#manga, #chapter] do |f| %>
Or
<%= form_for manga_chapter_path(#manga, #chapter) %>
And in your controller:
def new
#manga = Manga.find(params[:manga_id])
#chapter = Chapter.new
end
To help you after your comments:
In your create method:
def create
#manga = Manga.find(params[:manga_id])
#chapter = Chapter.new(chapter_params)
if #chapter.save
(params[:images] || []).each_with_index do |image, index|
#chapter.pejis.create(image: image, scan_number: index + 1)
end
redirect_to manga_chapter_path(#manga, #chapter), notice: 'Chapter was successfully created.'
else
render :new
end
end

Related

param is missing or the value is empty: room

i created an edit page to edit the room(model) and update the form to change the current name and current capacity to whatever we wish but i am getting an error
ActionController::ParameterMissing in RoomsController#edit
param is missing or the value is empty: room
rooms_controller.rb
class RoomsController < ApplicationController
before_action :set_room, only: %i[show edit update]
def index
#rooms = Room.all
end
def show
end
def new
#room = Room.new
end
def create
#room = Room.new(room_params)
respond_to do |format|
if #room.save
format.html { redirect_to room_url(#room), notice: "Room was created Successfully" }
else
format.html { render :new, status: :unprocessable_entity }
end
end
end
def edit
respond_to do |format|
if #room.update(room_params)
format.html { redirect_to room_url(#room), notice: "Room was successfully updated!" }
else
format.html { render :edit, status: :unprocessable_entity }
end
end
end
private
def set_room
#room = Room.find(params[:id])
end
def room_params
params.require(:room).permit(:name, :capacity)
end
end
edit.hml.erb
<h2>Edit Room</h2>
<%= render "form", room: #room %>
_form.html.erb
<%= form_with(model: room) do |form| %>
<% if room.errors.any? %>
<div style="color: red">
<h2><%= pluralize(room.errors.count, "errors") %> Prohibited this Room from saving</h2>
<ul>
<% room.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div>
<%= form.label :name, style: "display: block" %>
<%= form.text_field :name %>
</div>
<div>
<%= form.label :capacity, style: "display: block" %>
<%= form.number_field :capacity %>
</div>
<div>
<%= form.submit %>
</div>
<% end %>
i am using the same partial _form.html.erb for both new.html.erb and edit.html.erb , is it because of using same partial form for edit and new or there is some other reason?
new.html.erb
<h1>New Room</h1>
<%= render "form", room: #room %>
You're using the wrong action.
In Rails flavored REST the edit action responds to a GET /rooms/:id/edit request and just renders the form. It should also be idempotent. There is no room parameter since you're not responding to a form submission.
Updating the resource is done in the update method (PATCH /rooms/:id).
class RoomsController < ApplicationController
# ...
# you can actually completely omit this method
# Rails will implicitly render edit.html.erb anyways
# GET /rooms/1/edit
def edit
end
# PATCH /rooms/1
def update
# you don't need to use MimeResponds if you're only responding to HTML requests. KISS
if #room.update(room_params)
redirect_to #room, notice: "Room was successfully updated!"
else
render :edit, status: :unprocessable_entity
end
end
# ...
end

Get selected value from form.select

I have 2 models - project and todo, and the project contain many todos. I'm trying to write a form that would add a todo to a specific project, that's selected in the tray.
Unfortunately I get an error
Couldn't find Project with 'id'=
from todos_controller when i redirect to /todos
#project = Project.find(params[:project_id])
/projects/index.html.erb
<h1> Задачи </h1>
<% #projects.each do |project_name|%>
<h3><%= project_name.title %></h3>
<ul>
<% project_name.todos.each do |project_todo| %>
<li>
<p><%= project_todo.text %></p>
</li>
<% end %>
</ul>
<% end %>
<h1> Новая задача </h1>
<%= form_with scope: :todo, url: todos_path, local: true do |form| %>
<p>
<% form.label :text %><br>
<%= form.text_field :title, placeholder: "Название задачи" %>
</p>
<%= form.select( :project_id, options_from_collection_for_select(Project.all, :id, :title)) %>
<p>
ОТМЕНА
<%= link_to form.submit %>
</p>
<% end %>
projects_controller.rb
class ProjectsController < ApplicationController
def index
#projects = Project.all
respond_to do |format|
format.html
format.json {render json: #projects}
end
end
todos_controller.rb
class TodosController < ApplicationController
def index
#todos = Todo.all
respond_to do |format|
format.html
format.json {render json: #todos}
end
end
def update
end
def create
#project = Project.find(params[:project_id])
#todo = #project.todo.create(todo_params)
redirect_to projects_path
end
end
routes.rb
Rails.application.routes.draw do
resources :projects, :todos
root 'projects#index'
end
I also could not display the submit button as a text link.
modify create action as
def create
#project = Project.find(params[:todo][project_id])
#todo = #project.todo.create(todo_params)
redirect_to projects_path
end
if not works then check params hash from server log and check project_id is present in params or not.
Above will work but I think you do not need to find project if you modify create action as
def create
#todo = Todo.create(todo_params)
redirect_to projects_path
end
also define method as
def todo_params
params.require(:todo).permit(:project_id, :title)
end
Your controller expects a project_id parameter which is probably not passed! Try to add the project id to your params hash when you trigger the todos#create method
params[:project_id] is nil because the form you are submitting for todo, so you need to access project_id as
Project.find(params[:todo][project_id]) in create action.
So replace your create action as follow
def create
#project = Project.find(params[:todo][project_id])
#todo = #project.todo.create(todo_params)
redirect_to projects_path
end
Dont forget to include project_id in todo_params method.

Unable to assign a parent id to nested comments, using Ancestry gem (ruby on rails)

I am creating nested comments (like you find on Reddit). I am able to create parent comments, but when I try to create a child comment, it simply renders as a parent comment.
In my rails console, the "ancestry" field comes back "nil".
This is my comments controller:
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!
def show
#comment = Comment.find(params[:id])
end
def new
#link = Link.find(params[:link_id])
#comment = Comment.new(:parent_id => params[:parent_id])
#comments = Comment.all
end
def create
#link = Link.find(params[:link_id])
#parent = Link.find(params[:link_id]) if params[:link_id]
#parent = Comment.find(params[:comment_id]) if params[:comment_id]
#comment = #parent.comments.new(comment_params)
#comment.user = current_user
respond_to do |format|
if #comment.save
format.html { redirect_to #link, notice: 'Comment was successfully created.' }
format.json { render json: #comment, status: :created, location: #comment }
else
format.html { render action: "new" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
def destroy
#comment.destroy
respond_to do |format|
format.html { redirect_to :back, notice: 'Comment was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_comment
#comment = Comment.find(params[:id])
end
def comment_params
params.require(:comment).permit(:link_id, :body, :user_id)
end
end
Here is my _comment_form partial
<%= div_for(comment) do %>
<div class="comments_wrapper clearfix">
<div class="pull-left">
<p class="lead"><%= comment.body %></p>
<p><small>Submitted <strong><%= time_ago_in_words(comment.created_at) %> ago</strong> by <%= comment.user.email %></small></p>
<div id="reply" style="display:none;">
<%= form_for [#comment = Comment.new(:parent_id => params[:parent_id])] do |f| %>
<%= f.hidden_field :parent_id %>
<%= f.text_area :body %> <br>
<%= f.submit %>
<% end %>
</div>
</div>
<div class="actions btn-group pull-right">
<button onClick="$('#reply').show()" class="btn btn-sm btn-default">Reply</button>
<% if comment.user == current_user -%>
<%= link_to 'Destroy', comment, method: :delete, data: { confirm: 'Are you sure?' }, class: "btn btn-sm btn-default" %>
<% end %>
</div>
</div>
<% end %>
These are my routes
Rails.application.routes.draw do
resources :comments
devise_for :users
devise_for :installs
resources :links do
member do
put "like", to: "links#upvote"
put "dislike", to: "links#downvote"
end
resources :comments
end
root to: "links#index"
end
Had this problem before; the answer is here:
Ancestry gem in Rails and Mutli Nesting
The problem with ancestry (this is why we changed back to acts_as_tree) is that you have to define all the ancestors in the ancestry column (as opposed to just the parent_id column of acts_as_tree).
Thus, when you call the .children of an object (where you've literally just populated ancestry with top-level parents) is a list of children for that parent (no others).
What you need is to reference the entire ancestry line. This is quite tricky, but can be achieved using the code below:
#app/views/links/index.html.erb
<%= render #link.comments if #post.comments.any? %>
#app/views/links/_comment.html.erb
<%= comment.title %>
<%= render "form", locals: {link: #link} %>
<%= render comment.children if comment.has_children? # > adds recursion (multi level nesting) %>
#app/views/links/_form.html.erb
<%= form_for link.comments.new do |c| %>
<%= c.text_field :body %>
<%= c.submit %>
<% end %>
The controller is as follows:
#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
#link = Link.find params[:link_id]
#comment = #link.comments.new ancesrtry: parent(params[:parent_id])
end
private
def parent(param)
parents = Comment.find(param).pluck(:parent)
"#{parents}/#{param}" #-> ruby automatically returns last line
end
end
This should set the correct path for you, and the partials should give you the appropriate recursion required for multi level nesting.

Ruby on Rails app - Adding multiple dynamic input field

I'm a Rails newbie, and I have a RoR app that I'm working on, the app is supposed to allow invited guests to RSVP to a wedding.
I have allowed for fields to be dynamically added, in order to include additional guests (family of an invited guest). But when I add the dynamic field and add the names, only the last name is displayed in the index.
Is there anything specific I need to do to render all other names together in a field within the table?
This is my current controller thus far:
class GuestsController < ApplicationController
skip_before_filter :authenticate_user!, only: [:new, :create]
def index
#guests = Guest.all
end
def new
#guest = Guest.new
end
def create
#guest = Guest.all
#guest = Guest.create(guest_params)
if #guest.save
respond_to do |format|
format.html { redirect_to :back, notice: 'Thank you for replying' }
format.js
end
else
respond_to do |format|
format.html { render 'new' }
format.js
end
end
end
def destroy
#guest = Guest.find(params[:id])
#guest.destroy
redirect_to guests_path
end
private
def guest_params
params.require(:guest).permit(:status, :name, :message)
end
end
Place Guest in place of User
users controler
def new
#users = []
5.times do
#users << User.new
end
end
if params.has_key?("user")
User.create(users_params(params["user"]))
else
params["users"].each do |user|
if user["name"] != nil || user["age"] != nil
User.create(users_params(user))
end
end
end
def users_params(my_params)
my_params.permit(:name, :age)
end
users_form
<%= form_tag users_path do %>
<% #users.each do |user| %>
<%= fields_for 'users[]', user do |u| %>
<div class="field">
<%= u.label :name %><br>
<%= u.text_field :name %>
</div>
<div class="field">
<%= u.label :age %><br>
<%= u.number_field :age %>
</div>
<% end %>
<% end %>
<div class="actions">
<%= submit_tag %>
</div>
<% end %>

How can I add a related record whilst on its parents edit page?

I have a table of venues and offers. Each venue can have have many offers.
I would like to be able to add the offers to the venues from the venues edit page. So far I have this (code below) but its giving a "NoMethodError in Venues#edit, undefined method `model_name' for NilClass:Class" error.
venues edit page
(the div id="tabs-3" is a container in an accordion)
<div id="tabs-3">
<%= form_for [#venue, #offer] do |f| %>
<h2 class="venue_show_orange">Offers</h2>
<%= f.fields_for :offers do |offer| %>
<div class="add_offer">
<%= offer.text_field :title %><br>
</div>
<div class="button"><%= submit_tag %></div>
<% end %>
<% end %>
</div>
offers controller
class OffersController < ApplicationController
def new
#offer = Offer.new
end
def create
#offer = #venue.offers.create!(params[:offer])
#offer.venue = #venue
if #offer.save
flash[:notice] = 'Offer added'
redirect_to offers_path
else
render :action => :new
end
end
def edit
#offer = Offer.find(params[:id])
end
def update
#offer = Offer.find(params[:id])
#offer.attributes = params[:offer]
if #offer.save!
flash[:notice] = 'Offer updated successfully'
redirect_to offers_path(#offer)
end
end
end
venues controller
(nothing offer related in here - is this where I'm going wrong?)
class VenuesController < ApplicationController
protect_from_forgery :only => [:update, :delete, :create]
load_and_authorize_resource
def new
#venue = Venue.new
5.times { #venue.venuephotos.build }
end
def create
#venue = Venue.new params[:venue]
if #venue.save
flash[:notice] = 'Venue added'
redirect_to venues_path
else
render :action => :new
end
end
def edit
#venue = Venue.find(params[:id])
5.times { #venue.venuephotos.build }
end
def update
#venue = Venue.find(params[:id])
#venue.attributes = params[:venue]
if #venue.save!
flash[:notice] = 'Venue updated successfully'
redirect_to :back
end
end
end
Any help is much appreciated thanks very much!
edit
venues edit page
<div id="tabs-3">
<%= form_for #venue do |f| %>
<div class="edit_venue_details">
<h2 class="venue_show_orange">Offers</h2>
<%= render :partial => 'offers/offer', :collection => #venue.offers %>
<div class="clearall"></div>
<h2 class="edit_venue_sub_header">Add a new offer</h2>
<%= f.fields_for :offers do |offer| %>
<% if offer.object.new_record? %>
<p class="edit_venue">title: <br>
<%= offer.text_field :title, :class => "edit_venue_input" %></p>
<% end %>
<% end %>
</div>
<button class="submit_button" type="submit"> Save changes</button>
<% end %>
</div>
whats being displayed
however if I add a new offer, that will display correctly:
Some remarks:
1) Replace:
<%= form_for [#venue, #offer] do |f| %>
with:
<%= form_for #venue do |f| %>
Because offers data will be updated through the related venue, only one controller action will handle the form.
2) If you want to add some unexisting offers in this form, you shoud instantiate them the way you did with venuephotos
3) Show your Venue model. You should have at least:
accepts_nested_attributes_for :offers
Fixed with:
<%= f.fields_for :offers, #venue.offers.build do |offer| %>

Resources