undefined method `project' for nil:NilClass - ruby-on-rails

I have created project scaffold and stage scaffold with many to one association. Now I have added task scaffold with many to one association with stage scaffold. But I am not able to render task form correctly.
error
routes.rb:
resources :projects do
resources :stages do
resources :tasks
end
end
task form.html.erb
<%= form_with(model: task, url: projects_stages_tasks_path(#stages, #stages.project), local: true) do |form| %>
<% if task.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(task.errors.count, "error") %> prohibited this task from being saved:</h2>
<ul>
<% task.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :task_name %>
<%= form.text_field :task_name %>
</div>
<div class="actions">
<%= form.submit 'Create', :class=>'button primary small' %>
</div>
<% end %>
tasks_controller.rb
def index
#tasks = Task.all
end
def new
#task = Task.new
end

From what you wrote, I understand you're trying to create a task form as a nested resource. So I would do something like this: First of all, make sure you're setting #project and #stage variables in your tasks_controller:
before_action :set_project
before_action :set_stage
# ...
private
def set_project
#project = Project.find(params[:project_id])
end
def set_stage
#stage = #project.stages.find(params[:stage_id]) # Project#stages association is assumed to exist here
end
then, set your #task variable in the action itself, like this:
def new
#task = #stage.tasks.build # Stage#tasks association is assumed to exist here
end
then, in your view, you can use regular form, where you wouldn't have to specify the url on your own (well, I guess):
<%= form_with model: [#project, #stage, #task] do |f| %>
etc.

Related

not able to set project_id into databse in nested route

i have created a project scaffold with one to many association with responsibility. i am able to render responsibility form but i am not able to set project_id into responsibility table. i have created one to many association.
here are my code-
routes.rb
resources :projects do
resources :responsibilities
end
responsibility form.html.erb
<%= form_with(model: responsibility, url: [#project, responsibility], local: true) do |form| %>
<% if responsibility.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(responsibility.errors.count, "error") %> prohibited this responsibility from being saved:</h2>
<ul>
<% responsibility.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :responsibility_matrix %>
<%= form.text_field :responsibility_matrix %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
responsibilities_controller.rb
def new
#project = Project.find(params[:project_id])
#responsibility = Responsibility.new
end
Step by step
New app
rails new bookstore
Add scaffold author
rails g scaffold author name
Add scaffold book
rails g scaffold book name author:references
Updating routes
From
resources :books
resources :authors
To
resources :authors do
resources :books
end
Let's show link to new book in app/views/authors/show.html.erb, add
<%= link_to 'New book', new_author_book_path(#author) %> |
After create a first Author, and visiting http://localhost:3000/authors/1/books/new we have a erro that you have: NoMethodError in Books#new
undefined method `books_path'
To fix, first in BooksController add
before_action :set_author, only: [:new]
private
def set_author
#author = Author.find(params[:author_id])
end
And in app/views/books/_form.html.erb
<%= form_with(model: book, url:[#author, book], local: true) do |form| %>
Visiting again http://localhost:3000/authors/1/books/new
NameError in Books#new
undefined local variable or method `books_path'
Fix in app/views/books/new.html.erb
Change
<%= link_to 'Back', books_path %>
to
<%= link_to 'Back', author_books_path(#author) %>
Now we can render http://localhost:3000/authors/1/books/new
I think that here you got all you need

Rails: How to pass instance variables from a controller to render partial

I am having trouble passing an instance variable (#article) from a controller (articles_controller.rb) to a partial render (_form.html.erb) in Ruby.
Here is the error from being sent back:
`undefined method `errors' for nil:NilClass`
articles_controller.rb:
class ArticlesController < ApplicationController
def new
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit', :article => #article
end
end
def show
#article = Article.find(params[:id])
end
def index
#articles = Article.all
end
private
def article_params
params.require(:article).permit(:title, :text)
end
end
new.html.erb
<h1>New Article</h1>
<%= form_for :article, url: articles_path do |f|%>
<%= render partial: "form", :locals => {:article => #article} %>
<% end %>
<% link_to 'Back', articles_path %>
_form.html.erb
<% 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_messeages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br />
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
Any help would be appreciated
def new
#article = Article.new
end
<%= render partial: "form", collection: #article %>
or even
<%= form_for #article do |f|%>
<%= render 'form' %>
<% end %>
depends on your needs
I had this challenge when working on a Rails 6 application.
I wanted to use an instance variable in a partial (app/views/shared/_header.html.erb) that was defined in a different controller (app/controllers/categories_controller.rb).
Here's how I did it:
The instance variable that I wanted to use is #categories which is defined as:
# app/controllers/categories_controller.rb
class CategoriesController < ApplicationController
def index
#categories = Category.all
end
.
.
.
end
Firstly, I rendered the app/views/shared/_header.html.erb partial in the app/views/layouts/application.html.erb and passed the #categories instance variable into it this way:
<%= render partial: '/shared/header', locals: { categories: #categories } %>
And then I used the instance variable in the partial this way:
# app/views/shared/_header.html.erb
<% #categories.each do |category| %>
<%= link_to category do %>
<%= category.name %>
<% end %>
<% end %>
However, this will require a controller action that sets a #categories instance variable for every controller views that will use the partial.
If you want to make variables globally available in your controllers and views, this could help: Rails: Set a common or global instance variable across several controller actions
That's all.
I hope this helps
You should do like this, removing #. You are passing it to local variable article so you could access it with article not #article:
<% 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_messeages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br />
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
For more info, please take a look at passing-local-variables

Getting "param is missing or the value is empty: post" explained below

when i click new post and try to save a new post it gives me that error, then i go to the controller :
private
def posts_params
params.require(:post).permit(:title, :description)
end
and change 'require(:post)' to 'require(:posts' then i works
but then i try to edit the new post i just created and when i click to save it it gives me the same error, then i just change it back to 'required(:post)' and it works, why this is happening ? it's like a loop, if one works the other doesn't and to work i have to change that one thing
Controller:
class PostsController < ApplicationController
def index
#posts = Post.all
end
def edit
#posts = Post.find(params[:id])
end
def update
#posts = Post.find(params[:id])
if #posts.update(posts_params)
redirect_to #posts
else
render 'edit'
end
end
def new
#posts = Post.new
end
def create
#posts = Post.new(posts_params)
if #posts.save
redirect_to #posts
else
render 'new'
end
end
def show
#posts = Post.find(params[:id])
end
private
def posts_params
params.require(:post).permit(:title, :description)
end
end
view edit:
<h1>Editing post</h1>
<%= form_for(#posts) do |f| %>
<% if #posts.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#posts.errors.count, "error") %> prohibited
this post from being saved:
</h2>
<ul>
<% #posts.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 :description %><br>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Back', posts_path %>
view new:
<h1>New Article</h1>
<%= form_for :posts, url: posts_path do |f| %>
<% if #posts.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#posts.errors.count, "error") %> prohibited
this post from being saved:
</h2>
<ul>
<% #posts.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 :description %><br>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Back', posts_path %>
can someone point the problem out ?
You are mixing
form_for(#posts) do |f|
and
form_for :posts, url: posts_path
In your forms.
the :posts version will generate params[:posts] and the #posts version will generate params[:post]. Hence the issue you are seeing. Make sure you posts_params is as follows.
def posts_params
params.require(:post).permit(:title, :description)
end
then just change both of your forms to be
<%= form_for(#posts) do |f| %>
rails will figure out which to call automatically for you, so you will not have to specify the paths..
On a side note, I would probably change #posts to be #post everywhere but the index action, just so that it makes more sense, Since in new,edit,etc.. you are dealing with a singular post.
Since rails is looking at the Model/class of the variable when generating the routes (When given an instance variable) the name of the variable doesn't matter to the framework, but makes it easier (in my opinion) for the programmer to understand

How to retrieve id sent from a link_to in rails

I am trying to to edit a form through a reveal-modal. So i have multiple posts.
When I click the link 'Edit' it will reveal a div and display a form inside that is repopulated with the information. However, I don't know how to pass the post id into the form it will know which post to edit.
If i try to render the partial form I get this error:
undefined method `model_name' for Post::ActiveRecord_Relation:Class
All my information are on a controller view that is called Dashboard
controllers/dashboards_controller.rb
class DashboardsController < ApplicationController
def index
#profile = Profile.find(current_user)
#profileAll = Profile.all
#post = Post.all
end
def show
end
def edit
#profile =Profile.find(current_user)
#post = #profile.post.find(params[:id])
end
end
controllers/posts_controller.rb
class PostsController < ApplicationController
def create
#profile = Profile.find(current_user)
#post = #profile.post.create(post_params)
redirect_to dashboards_path(current_user)
end
def destroy
#post =Profile.find(params[:profile_id])
#post = profile.post.find(params[:id])
#post.destroy
redirect_to dashboards_path(current_user)
end
def show
#profile =Profile.find(current_user)
#post = #profile.post.find(params[:id])
end
def edit
#profile =Profile.find(current_user)
#post = #profile.post.find(params[:id])
end
def update
#post = profile.post.find(params[:id])
if #post.update(post_params)
redirect_to dashboards_path(current_user)
else
render 'edit'
end
end
private
def post_params
params.require(:post).permit(:title, :content)
end
end
posts/_form2.html.erb
<%= form_for #post do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited
this post from being saved:</h2>
<ul>
<% #post.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 :content %><br>
<%= f.text_area :content %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
routes.rb
Rails.application.routes.draw do
get 'homepages/index'
resources 'dashboards' do
resources 'posts'
end
#get 'users/sign_in'
resources 'profiles' do
resources 'posts'
end
devise_for :users, :controller => {:registrations => "users/registrations"}
devise_scope :user do
root :to => 'devise/sessions#new'
end
end
Dashboards/index.html.erb
<% #post.each do |post| %>
<div class="panel">
<%= #profileAll.find(post.profile_id).name %>
<hr>
<h5><%= post.title %></h5>
<p><%= post.content %></p>
<%# link_to "Edit", edit_dashboard_post_path(current_user,[post.profile, post]) %>
<%= link_to "Edit", {id: #post},'data-reveal-id' => 'edit-post' %>
</div>
<% end %>
<div id="edit-post" class="reveal-modal" data-reveal>
<%= render 'posts/form2' %>
<a class="close-reveal-modal">×</a>
</div>
Well, it simply does not work that way. First, you have in your controller #post = Post.all and within your _form2.html.erb you want to render form for a collection. That should be:
# index.html.erb
<div id="edit-post" class="reveal-modal" data-reveal>
<%= render :partial => 'posts/form2', collection: #posts %>
<a class="close-reveal-modal">×</a>
</div>
#dashboard controller:
def index
#...
#posts = Post.all
end
_form2.html.erb:
Every #post object instance has to be replaced with form2. Read more here: http://api.rubyonrails.org/classes/ActionView/PartialRenderer.html about rendering a collection.
However, consider a case when you have hundreds of posts. Then, for each post, a partial is rendered. That would be very inefficient so instead, consider an asynchronous request which will load only one post the user requested.

Using a form to populate a database and land on a page with the information submitted

I have a form on my new view that takes in "url" and "title". When I submit my "url" & "title" I am taken to a blank create view. Ideally I would like to populate my database and land on a page that shows the title and link for that project.
This is my controller as it stands:
class LinksController < ApplicationController
def index
end
def new
#link = Link.new
end
def create
end
end
And this is the form:
<h1> This is New page for links </h1>
<%= form_for(#link) do |f| %>
<% if #link.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#link.errors.count, "error") %> prohibited this link from being saved:</h2>
<ul>
<% #link.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :url %><br />
<%= f.text_field :url %>
</div>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
How would I go about creating my methods(actions) to populate the database and then render what I am seeking? Ideally I'd like to see the flow behind how to think about the problem and the final code so that I can reverse engineer it.As long as I see it once I should be able to do it on my own next time.
You just have to do this
def create
#link = Link.new(params[:link])
if #link.save
redirect_to #link
else
render :new
end
end
def show
#link = Link.find(param[:id])
end
In routes.rb you will want to make sure you have the routes for this controller and its actions.
resources :links
That will provide you the standard CRUD HTTP methods with matching routes.

Resources