undefined method ` for nil:NilClass - html

I am trying to display the new form page from another controller's page, I am used nested resources.
I am getting this error
undefined method `sublet_posts' for nil:NilClass
Student Model
class Student < ApplicationRecord
has_many :sublet_posts, :dependent => :destroy
end
Sublet_post model
class SubletPost < ApplicationRecord
belongs_to :student
end
route.rb
resources :students do
resources :sublet_posts
end
Student show view
<p id="notice"><%= notice %></p>
...
...
...
<h3>Sublet Post</h3>
<% #student.sublet_posts.each do |sublet_post| %>
<%= sublet_post.description %>
<%= link_to "Edit", edit_student_sublet_post_path(#student, sublet_post) %>
<% end %>
<h3>Add Sublet Post</h3>
<%= link_to "Add", new_student_sublet_post_path(#student)%>
Sublet_Post Controller
class SubletPostsController < ApplicationController
before_action :set_sublet_post, only: [:edit, :update, :destroy]
# POST /sublet_posts
# POST /sublet_posts.json
def create
#student = Student.find(params[:student_id])
#sublet_post = #student.create(sublet_post_params)
#sublet_post.student_id = current_member_id
redirect_to student_path(#student)
end
# PATCH/PUT /sublet_posts/1
# PATCH/PUT /sublet_posts/1.json
def update
#student = Student.find(params[:student_id])
#sublet_post = #student.sublet_posts.update(sublet_post_params)
redirect_to student_path(#student)
end
private
# Use callbacks to share common setup or constraints between actions.
def set_sublet_post
#sublet_post = SubletPost.find(params[:id])
end
# Only allow a list of trusted parameters through.
def sublet_post_params
params.require(:sublet_post).permit(......)
end
end
Sublet Post form view
<%= form_for [#student, #student.sublet_posts.build] do |form| %>. <----------------- Error
<% if sublet_post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(sublet_post.errors.count, "error") %> prohibited this sublet_post from being saved:</h2>
<ul>
<% sublet_post.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
Any help will be very appreciated. I didn't think the student controller was needed so I left it out.

Related

What's wrong with my form in Ruby on Rails?

I'm trying to implement a prayer request and prayer response form, much like a micropost with a comment on it. The prayer requests are created and deleted as expected, but when I try to post a prayer response, it just reloads the page with no errors and no flash saying that the post was successful. This behavior happens wether the post is valid or not (no errors for a blank response, just a reload of the page) When I use the rails console, I'm able to build and save a prayer response successfully, and it shows up on rails server. What's wrong with my form? Based on the server log, I see that when I try to post a prayer response, it's using the RequestsController instead of the PrayerResponsesController. How do I fix this?
Here's my server log errors:
Started POST "/requests" for 127.0.0.1 at 2023-01-18 16:24:36 -0600
Processing by RequestsController#create as TURBO_STREAM
Parameters: {"authenticity_token"=>"[FILTERED]", "content"=>"Prayer response...", "request_id"=>"150", "commit"=>"Respond in Prayer"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
↳ app/helpers/sessions_helper.rb:18:in `current_user'
CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
↳ app/helpers/sessions_helper.rb:18:in `current_user'
Completed 400 Bad Request in 4ms (ActiveRecord: 0.1ms | Allocations: 2115)
ActionController::ParameterMissing (param is missing or the value is empty: request
Did you mean? request_id):
Here's my code:
controllers/prayer_responses_controller.rb
class PrayerResponsesController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy
def create
#prayer_response = current_user.prayer_responses.build(prayer_response_params)
if #prayer_response.save
flash[:success] = "Prayer Response created!"
redirect_back(fallback_location: root_url)
else
render 'static_pages/requests', status: :unprocessable_entity
end
end
def destroy
#prayer_response.destroy
flash[:success] = "Prayer Response deleted"
redirect_back_or_to( root_url, status: :see_other )
end
private
def prayer_response_params
params.require(:prayer_response).permit(:content, :request_id)
end
def correct_user
#prayer_response = current_user.prayer_responses.find_by(id: params[:id])
redirect_to root_url, status: :see_other if #prayer_response.nil?
end
end
views/static_pages/requests.html.erb
<% provide(:title, "Prayer Requests") %>
<div class="row">
<aside class="col-md-4">
<section class="request-form">
<%= render 'shared/request_form' %>
</section>
</aside>
<div class="col-md-8">
<h3>Prayer Requests</h3>
<% if Request.all != nil %>
<%= render Request.all %>
<% end %>
</div>
</div>
views/requests/_request.html.erb
<li id="request-<%= request.id %>" class="requests">
<%= link_to gravatar_for(request.user, size: 50), request.user %>
<span class="user"><%= link_to request.user.name, request.user %></span>
<span class="content"><%= request.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(request.created_at) %> ago.
<% if current_user?(request.user) %>
<%= link_to "delete", request, data: { "turbo-method": :delete,
"turbo-confirm": "Are you sure?"} %>
<% end %>
</span>
<% if current_user != nil %>
<span>
<%= render 'shared/prayer_response_form', request_id: request.id %>
</span>
<span>
<% if request.prayer_responses.any? %>
<ol class="prayer_responses">
<% request.prayer_responses.reverse.each do |prayer_response| %>
<%= render prayer_response %>
<% end %>
</ol>
<% end %>
</span>
<% end %>
</li>
views/prayer_responses/_prayer_response.html.erb
<li id="prayer_response-<%= prayer_response.id %>">
<%= link_to gravatar_for(prayer_response.user, size: 30), prayer_response.user %>
<span class="user"><%= link_to prayer_response.user.name, prayer_response.user %></span>
<span class="content"><%= prayer_response.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(prayer_response.created_at) %> ago.
<% if current_user?(prayer_response.user) %>
<%= link_to "delete response", prayer_response, data: { "turbo-method": :delete,
"turbo-confirm": "Are you sure?"} %>
<% end %>
</span>
</li>
views/shared/_prayer_response_form.html.erb
<%= form_with(model: #prayer_response) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<center>
<div class="field">
<%= f.text_area(:content, placeholder: "Respond to this prayer request...") %>
</div>
<div><%= f.hidden_field :request_id, value: request_id %></div>
<%= f.submit "Respond in Prayer", class: "btn btn-primary" %>
</center>
<% end %>
models/prayer_response.rb
class PrayerResponse < ApplicationRecord
belongs_to :user
belongs_to :request
default_scope -> { order( created_at: :desc) }
validates :user_id, presence: true
validates :request_id, presence: true
validates :content, presence: true, length: { maximum: 500 }
end
models/request.rb
class Request < ApplicationRecord
belongs_to :user
has_many :prayer_responses, dependent: :destroy
default_scope -> { order(created_at: :desc) }
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 280 }
end
db/migrate/20230113172701_create_prayer_responses.rb
class CreatePrayerResponses < ActiveRecord::Migration[7.0]
def change
create_table :prayer_responses do |t|
t.text :content
t.references :user, null: false, foreign_key: true
t.references :request, null: false, foreign_key: true
t.timestamps
end
add_index :prayer_responses, [:user_id, :request_id, :created_at]
end
end
db/migrate/20230107204925_create_requests.rb
class CreateRequests < ActiveRecord::Migration[7.0]
def change
create_table :requests do |t|
t.text :content
t.references :user, null: false, foreign_key: true
t.timestamps
end
add_index :requests, [:user_id, :created_at]
end
end
config/routes.rb
root "static_pages#home"
get "/help", to: "static_pages#help"
get "/about", to: "static_pages#about"
get "/contact", to: "static_pages#contact"
get "/new_public_prayers", to: "static_pages#new_public_prayers"
get "/signup", to: "users#new"
get "/login", to: "sessions#new"
post "/login", to: "sessions#create"
delete "/logout", to: "sessions#destroy"
resources :users do
member do
get :following, :followers
end
end
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
resources :prayers, only: [:create, :destroy]
resources :requests, only: [:create, :destroy]
resources :prayer_responses, only: [:create, :destroy]
resources :comments, only: [:create, :destroy]
resources :private_prayers, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
get "/private_prayers", to: "static_pages#private_prayers"
get "/prayers", to: "static_pages#home"
get "/comments", to: "static_pages#home"
get "/requests", to: "static_pages#requests"
get "/prayer_responses", to: "static_pages#requests"
end
The answer, actually, was in the static_pages_controller.rb file... I needed to add #prayer_response = current_user.prayer_responses.build to the requests page's function...
class StaticPagesController < ApplicationController
def home
if logged_in?
#prayer = current_user.prayers.build
#comment = current_user.comments.build
#feed_items = current_user.feed.paginate(page: params[:page])
end
end
def help
end
def about
end
def contact
end
def new_public_prayers
end
def private_prayers
if logged_in?
#private_prayer = current_user.private_prayers.build
else
redirect_to root_url
end
end
def requests
if logged_in?
#request = current_user.requests.build
#prayer_response = current_user.prayer_responses.build
else
redirect_to root_url
end
end
end
This made sure that the proper controller was followed when building a new prayer response, etc.

twitter clone - trying to show the users username next to their tweet on tweets index - devise

I'm trying to create a twitter clone. I'm at the point where a user can post a tweet and it shows the content and the time it was posted. However i want it so the username is also next to the tweet of whoever tweeted it.
i'm unsure how to do this as the error is currently 'Couldn't find User without an ID' in my tweet controller create method. I'm also not sure of the syntax to display the username in index.html.erb.
thanks.
class TweetsController < ApplicationController
def index
#tweets = Tweet.all.order("created_at DESC")
#tweet = Tweet.new
# #user = User.find(params[:id])
end
def show
#tweet = Tweet.find(params[:id])
end
def new
# #tweet = Tweet.new
end
def create
#user = User.find(params[:id])
#tweet = Tweet.new(tweet_params)
#tweet.user = #user
if #tweet.save
redirect_to tweets_path
end
end
def edit
#tweet = Tweet.find(params[:id])
end
def update
#tweet = Tweet.find(params[:id])
#tweet.update(tweet_params)
redirect_to tweets_path
end
private
def tweet_params
params.require(:tweet).permit(:user_id,:content)
end
end
<h1>TWEETS</h1>
<%# #users.each do |user| %>
<%#= user.username %>
<%# end %>
<%= simple_form_for #tweet, id: "form-submit" do |f| %>
<%= f.input :content, label: "Tweet" %>
<%= f.button :submit, class: "btn btn-danger" %>
<% end %>
<br>
<% #tweets.each do |tweet| %>
<ul>
<li>
<%= tweet.created_at.strftime("%B %d %Y, %l:%M%P") %> <br>
<%= tweet.content %>
<%#= tweet.user.username %>
<%#= tweet.user.username %>
</li>
</ul>
<% end %>
You need to set the relation between your users and tweets table
in your tweet model add
class Tweet < ApplicationRecord
belongs_to :user
end
and in your user model
class User < ApplicationRecord
has_many :tweets
end
rails g migration AddUserIdToMessages and in this migration
def change
add_column :tweets, :user_id, :integer
end
After that you can user <%= tweet.user.username %>in your view to show the username
My test :
Controller
class TweetsController < ApplicationController
def index
#tweets = Tweet.all.order("created_at DESC")
end
end
Model
class Tweet < ApplicationRecord
belongs_to :user
end
View (index.html.erb)
<% #tweets.each do |tweet| %>
<ul>
<li>
<%= tweet.created_at.strftime("%B %d %Y, %l:%M%P") %> <br>
<p> Content : <%= tweet.content %></p>
Username : <%= tweet.user.username %>
</li>
</ul>
<% end %>
Route
Rails.application.routes.draw do
get 'tweet/index', to: 'tweets#index'
end
seed.rb (for testing)
User.create({username: "myName"})
Tweet.create({content: "hello",user_id: 1})
and run rake db:seed
and dont forget to add
def change
add_column :tweets, :user_id, :integer
end
In the generated migration.

Incorrect HTML when pre-populating nested forms in Rails 5.1

I have a Rails 5.1 app that consumes the Google Books API and I need to pre-populate nested fields in a form. There are two ways to create a Book.
Firstly, through the normal /books/new form, which accepts_nested_attributes_for :authors with a has_many: through association. Here I am using cocoon gem and everything is working great.
Secondly, a user can create a Book by searching the Google Books API using an ISBN number. This data then pre-populates a form before being submitted to the create action in the BooksController. I have managed to get this working great apart from the ability to correctly submit the nested Author data.
I currently have each author populate a field in the form, yet when I come to submit the data only the last item in the author array (in the case of a book with multiple authors) gets saved.
I believe this is because the form html has the same name and id for both fields as below. How do I get this form to submit both authors?
<input value="John J. Ratey" type="text" name="book[authors_attributes][0][name]" id="book_authors_attributes_0_name">
<input value="Richard Manning" type="text" name="book[authors_attributes][0][name]" id="book_authors_attributes_0_name">
books_controller.rb
class BooksController < ApplicationController
before_action :authenticate_user!
before_action :set_book, except: [:index, :new, :create, :new_book, :submit_book]
def create
#book = current_user.books.create(book_params)
#book.authors.each {|author| author.user_id = current_user.id}
if #book.save
redirect_to book_path(#book)
else
render :new
end
end
def new_book
end
def submit_book
#book = Book.new
#book.authors.new
#response = GoogleBooks.new(params[:q], #book)
end
private
def set_book
#book = Book.find(params[:id])
end
def book_params
params.require(:book).permit(:title, :subtitle, :description, author_ids:[], authors_attributes: [:id, :name, :_destroy])
end
end
book.rb
class Book < ApplicationRecord
has_many :book_authors
has_many :authors, through: :book_authors
accepts_nested_attributes_for :authors, allow_destroy: true
validates :title, presence: true
validates_associated :authors
end
google_books.rb
class GoogleBooks
include HTTParty
base_uri 'https://www.googleapis.com/books/v1'
def initialize(isbn, book)
#query = self.class.get("/volumes?q=isbn:#{isbn}")
#book = book
end
def title
#query['items'].first['volumeInfo']['title']
end
def subtitle
#query['items'].first['volumeInfo']['subtitle']
end
def description
#query['items'].first['volumeInfo']['description']
end
def authors
#query['items'].first['volumeInfo']['authors']
#=> ['John J. Ratey', 'Richard Manning']
end
end
submit_book.html.erb
<%= form_for #book do |f| %>
<%= f.text_field :title, value: #response.title %>
<%= f.text_field :subtitle, value: #response.subtitle %>
<%= f.text_field :description, value: #response.description %>
<%= f.fields_for :authors, #book.authors.build do |authors_fields| %>
<% #response.authors.each do |author| %>
<%= authors_fields.text_field :name, value: author %>
<% end %>
<% end %>
<%= f.submit %>
Worked it out.
Was a case of changing
<%= f.fields_for :authors, #book.authors.build do |authors_fields| %>
<% #response.authors.each do |author| %>
<%= authors_fields.text_field :name, value: author %>
<% end %>
<% end %>
to this
<% #response.authors.each do |author| %>
<%= f.fields_for :authors, #book.authors.build do |authors_fields| %>
<%= authors_fields.text_field :name, value: author %>
<% end %>
<% end %>
Which produces the following correct HTML:
<input value="John J. Ratey" type="text" name="book[authors_attributes][0][name]" id="book_authors_attributes_0_name">
<input value="Richard Manning" type="text" name="book[authors_attributes][1][name]" id="book_authors_attributes_1_name">

How to show all the Users who have liked my post

I apologize for the newbie questions still relatively new to rails. I'm trying to show all the users who have liked my specific posts. I took a look at this similar question How to list the users who LIKE a given Post but it couldn't solve my problem. I listed below all the relevant simple code - thank you so much guys!!
Items Controller
class ItemsController < ApplicationController
before_action :authenticate_user!, only: [:new, :create]
before_action :set_item, only: [:show, :edit, :update, :destroy, :share]
def index
#items = Item.order("created_at DESC")
end
end
Index.html.erb
<% if user_signed_in? %>
<%= image_tag current_user.avatar, width: 70, class: "css-style" %>
<br>
<strong><%= link_to current_user.username, current_user, class: "profile-style" %></strong>
<ul><!--Trying to show all the users who have liked my specific posts here -->
<% item.likes.each do |like| %>
<li> <%= link_to(like.user.username, like.user) %></li>
<% end %>
</ul>
<br>
<br>
<% else %>
<%= link_to 'Login/SignUp', new_user_session_path %>
<% end %>
<% #items.each do |item| %>
<%= image_tag item.avatar.url(:medium), class: "block" %>
<div>
<%= render partial: "likes", locals: {item: item} %></span><%= item.likes_count %>
</div>
<% end %>
Items.rb
class Item < ApplicationRecord
has_many :likes, :counter_cache => true
belongs_to :user
has_attached_file :avatar, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\z/
end
User.rb
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, omniauth_providers: [:facebook]
has_many :likes
has_attached_file :avatar, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\z/
def likes?(post)
post.likes.where(user_id: id).any?
end
end
Users Controller
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy, :share]
def index
#users = User.all
end
def show
#user = User.find(params[:id])
#items = Item.all
end
private
def set_user
#user = User.find(params[:id])
end
def item_params
params.require(:item).permit(:product, :amount, :city_id, :avatar)
end
end
Like.rb
class Like < ApplicationRecord
belongs_to :item, :counter_cache => true
belongs_to :user
end
Likes Controller
class Items::LikesController < ApplicationController
before_action :authenticate_user!
before_action :set_book
def create
#item.likes.where(user_id: current_user.id).first_or_create
respond_to do |format|
format.html {redirect_to #item}
format.js
end
end
def destroy
#item.likes.where(user_id: current_user.id).destroy_all
respond_to do |format|
format.html {redirect_to #item}
format.js
end
end
private
def set_book
#item = Item.find(params[:item_id])
end
end
Logs
Processing by ItemsController#index as HTML
Rendering items/index.html.erb within layouts/application
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Item Load (0.3ms) SELECT "items".* FROM "items" ORDER BY created_at DESC
Rendered items/index.html.erb within layouts/application (287.6ms)
Completed 500 Internal Server Error in 313ms (ActiveRecord: 0.6ms)
ActionView::Template::Error (undefined local variable or method `item' for #<#:0x007f9afbfd14f0>
Did you mean? item_url
items_url
item_path
#items):
5:
6: <%= link_to current_user.username, current_user, class: "profile-style" %>
7:
8: <% item.likes.each do |like| %>
9: <%= link_to(like.user.username, like.user) %>
10: <% end %>
11:
app/views/items/index.html.erb:8:in `_app_views_items_index_html_erb___2312434021832006771_70151814680620'
Rendering /usr/local/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb within rescues/layout
Rendering /usr/local/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_source.html.erb
Rendered /usr/local/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_source.html.erb (8.3ms)
Rendering /usr/local/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
Rendered /usr/local/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (3.3ms)
Rendering /usr/local/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
Rendered /usr/local/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.2ms)
Rendered /usr/local/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb within rescues/layout (94.4ms)
In items/index.html.erb you are referencing #item.likes.each on line 9, but the instance variable #item has not been set in items_controller#index. You have only defined #items, hence the error you are receiving about nil not responding to #likes.
If you want to see the likes for all items, there are a number of ways to achieve this with Arel.
It's a simple mistake. I think the problem is with your partial.. you're calling the partial with locals and inside your template code you are referring to it with #item instead of item, here item is not an instance variable.
<% #items.each do |item| %>
<%= image_tag item.avatar.url(:medium), class: "block" %>
<div>
<%= render partial: "likes", locals: {item: item} %></span><%= item.likes_count %>
</div>
<% end %>
The thing is when you render a partial with locals you need to use the locals as normal variables not as instance variables.
This should work.
<% item.likes.each do |like| %>
<li> <%= link_to(like.user.username, like.user) %></li>
<% end %>
You need one more table(model) "likes" and association has-many-through. Something like this:
class Item
has_many :likes
has_many :users, through: :likes
end
class Like
belongs_to :user
belongs_to :item
end
class User
has_many :likes
has_many :items
has_many :liked_items, through: :likes
end

Rails: Issue with recieving nested forms with has many through join

I seem to be having a problem with receiving products through my join table, it's giving me a strange error as it seems to be receiving no ID for my order. I can only assume that this is because the order has not been created yet, but I am creating the order during this step anyway, so the order doesn't have an ID yet. So this is my problem.
Here is the error I recieve:
ActiveRecord::RecordNotFound in OrdersController#create
Couldn't find Product with ID=1 for Order with ID=
Rails.root: /BillingSystem
Application Trace | Framework Trace | Full Trace
app/controllers/orders_controller.rb:10:in `new'
app/controllers/orders_controller.rb:10:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"jE2wdERoxE7PKwBhN60KAfguxwAq8qdW4wbru51SMFg=",
"order"=>{"client_id"=>"1",
"products_attributes"=>{"1368396234677"=>{"id"=>"1",
"_destroy"=>"false"}}},
"commit"=>"Create Order"}
Show session dump
Show env dump
Response
Headers:
None
New Order View:
<% if current_user %>
<div id="dashboard">
<div id="logo"></div>
<table id="go_back_link_container">
<tr>
<td>
<div class="go_back_link">
<%= link_to "<- Go Back", "/orders/view" %>
</div>
</td>
<td>
<div id="user_display">
Logged in as <%= current_user.email %>.
<%= link_to "Log out", log_out_path %>
</div>
</td>
</tr>
</table>
<%= form_for #order, method: :post do |f| %>
<% if #order.errors.any? %>
<div class="error_messages">
<% for message in #order.errors.full_messages %>
* <%= message %> <br>
<% end %>
</div>
<% end %>
<p>
<%= f.label 'Select The Client' %><br />
<%= select :order, :client_id, Client.all().collect { |c| [ (c.firstname + " " + c.surname), c.id ] } %>
</p>
<%= f.fields_for :products do |pf| %>
<% #render 'product_fields', f: builder %>
<% end %>
<%= link_to_add_fields "Add Product", f, :products %>
<p class="button"><%= f.submit %></p>
<% end %>
<% flash.each do |name, msg| %>
<%= content_tag :div, "* " + msg, :id => "flash_#{name}" %><br />
<% end %>
<div id="copyright-notice"><div id="copyright_border">Copyright © Conner McCabe, all rights reserved.</div></div>
</div>
<% else %>
<script type="text/javascript">
window.location="<%= root_url %>"
</script>
<% end %>
Order Model:
class Order < ActiveRecord::Base
has_many :orderedproducts
has_many :products, through: :orderedproducts
has_one :client
attr_accessible :client_id, :order_total, :delivery_date, :products, :products_attributes
accepts_nested_attributes_for :products, :allow_destroy => true
before_save :generate_total
def generate_total
self.order_total = self.products.map(&:product_price).sum
end
end
Orders Controller:
class OrdersController < ApplicationController
def view
#orders = Order.all
end
def new
#order = Order.new
end
def create
#order = Order.new(params[:order])
if #order.save
redirect_to '/orders/view', :notice => "Order Created!"
else
render "new"
end
end
end
Product Fields Partial:
<fieldset>
<%= f.select :id, Product.all().collect {|p| [ p.product_name, p.id ] } %>
<%= f.hidden_field :_destroy %>
<%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>
Products Model:
class Product < ActiveRecord::Base
#This line makes these elements accessible outside of the class.
attr_accessible :product_name, :product_price, :product_quantity, :product_supplier
has_many :orderedproducts
has_many :orders, through: :orderedproducts
#These attributes ensure that the data entered for each element is valid and present.
validates_presence_of :product_name
validates_presence_of :product_price
validates_numericality_of :product_price
validates_presence_of :product_quantity
validates_numericality_of :product_quantity
validates_presence_of :product_supplier
end
Application Helper:
module ApplicationHelper
def link_to_add_fields(name, f, association)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize + "_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
end
Ordered Products Model:
class Orderedproduct < ActiveRecord::Base
attr_accessible :order_id, :product_id, :quantity_ordered
belongs_to :order
belongs_to :product
end
I have listed every possible file that could contain an error, I know it's a bit excessive, but it's everything that is to do with it and better I include it than not at all.
I also followed this railscast guide: http://railscasts.com/episodes/196-nested-model-form-revised
To get to where I am, I edited it slightly so that it was suitable for my application.
Thanks in advance.
We had a similar issue on a project, except the relation was singular. The problem is that ActiveRecord is looking for an existing association; something like order.products.find(1). Since order is as new record this doesn't work.
You could create your own products_attributes= method and define the correct behaviour. But I think that you could just use nested attributes for the join model (Orderedproduct) instead of Product.
class Order
accepts_nested_attributes_for :orderedproducts
end
Then adjust the form fields appropriately. In the new form
f.fields_for :products do |pf| becomes f.fields_for :orderedproducts do |pf|
In the fields partial
<%= f.select :id, Product.all().collect {|p| [ p.product_name, p.id ] } %> becomes <%= f.select :product_id, Product.all().collect {|p| [ p.product_name, p.id ] } %>