Undefined local variable or method ajax render partial rails - ruby-on-rails

I'm trying to add ajax to my comment form submission and I've run into an error when I'm trying to render a partial and I don't know how to solve it. I have everything set up properly and comments get created fine. But then I try to render the partial for the comments and I get this error:
undefined local variable or method `each' for #<#<Class:0xae4d760>:0xae59a78>
My create.js.erb
$("#comm_form_wrap").html("<%= escape_javascript(render :partial => "statuses/comment_form") %>");
$('#comment_box').val('');
$("#comments_wrap").html("<%= escape_javascript(render :partial => "statuses/comments") %>")
When I try to render statuses/comments is causing the error.
Here's my partial:
<% #comments.each do |comment| %>
<div class="com_con">
<%= Rinku.auto_link(comment.content).html_safe %>
</div>
<% end %>
So then I tried passing the variables like this
$("#comments_wrap").html("<%= escape_javascript(render :partial => "statuses/comments", :locals => {:comment => comment}) %>")
but it gives this error
undefined local variable or method `each' for #<#<Class:0xae4d760>:0xae59a78>
Not sure what I'm missing here, I'm sure it's something small. Can anyone help me?
View
<% if member_signed_in? %>
<div id="comm_form_wrap">
<%= render "comment_form" %>
</div>
<div id="comments_wrap">
<%= render "comments" %>
</div>
<% end %>
**Edit**
comments_controller.rb
class CommentsController < ApplicationController
before_filter :authenticate_member!
before_filter :load_commentable
before_filter :find_member
def index
redirect_to root_path
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(params[:comment])
#comment.member = current_member
respond_to do |format|
if #comment.save
format.html { redirect_to :back }
format.json
format.js
else
format.html { redirect_to :back }
format.json
format.js
end
end
end
def destroy
#comment = Comment.find(params[:id])
respond_to do |format|
if #comment.member == current_member || #commentable.member == current_member
#comment.destroy
format.html { redirect_to :back }
else
format.html { redirect_to :back, alert: 'You can\'t delete this comment.' }
end
end
end
private
def load_commentable
klass = [Status, Medium, Project, Event, Listing].detect { |c| params["#{c.name.underscore}_id"] }
#commentable = klass.find(params["#{klass.name.underscore}_id"])
end
def find_member
#member = Member.find_by_user_name(params[:user_name])
end
end
statuses_controller
def show
#status = Status.find(params[:id])
#commentable = #status
#comments = #commentable.comments.order('created_at desc').page(params[:page]).per_page(15)
#comment = Comment.new
respond_to do |format|
format.html # show.html.erb
format.json { redirect_to profile_path(current_member) }
format.js
end
end
Logs
Processing by StatusesController#show as HTML
Parameters: {"id"=>"86"}
[1m[35mMember Load (1.0ms)[0m SELECT "members".* FROM "members" WHERE "members"."user_name" IS NULL LIMIT 1
[1m[36mStatus Load (0.0ms)[0m [1mSELECT "statuses".* FROM "statuses" WHERE "statuses"."id" = ? LIMIT 1[0m [["id", "86"]]
[1m[35mComment Load (2.0ms)[0m SELECT "comments".* FROM "comments" WHERE "comments"."commentable_id" = 86 AND "comments"."commentable_type" = 'Status' ORDER BY created_at desc LIMIT 15 OFFSET 0
[#<Comment id: 82, content: "and why not try again ha", commentable_id: 86, commentable_type: "Status", member_id: 1, created_at: "2014-06-26 06:27:05", updated_at: "2014-06-26 06:27:05">]
[1m[36mMember Load (1.0ms)[0m [1mSELECT "members".* FROM "members" WHERE "members"."id" = 1 LIMIT 1[0m
[1m[35mCACHE (0.0ms)[0m SELECT "members".* FROM "members" WHERE "members"."id" = 1 LIMIT 1
[1m[36m (0.0ms)[0m [1mSELECT COUNT(*) FROM "comments" WHERE "comments"."commentable_id" = 86 AND "comments"."commentable_type" = 'Status'[0m
Rendered statuses/_comment_form.html.erb (8.0ms)
[1m[35mCACHE (0.0ms)[0m SELECT "members".* FROM "members" WHERE "members"."id" = 1 LIMIT 1
Rendered statuses/_comments.html.erb (95.0ms)
Rendered statuses/show.html.erb within layouts/application (406.0ms)
Rendered layouts/_query.html.erb (108.0ms)
Rendered search/_search.html.erb (22.0ms)
Rendered layouts/_menu.html.erb (592.0ms)
Completed 200 OK in 2956ms (Views: 2312.1ms | ActiveRecord: 10.0ms | Solr: 0.0ms)

Problem is your partial is calling #comments.each:
<% #comments.each do |comment| %>
2 issues:
#comments doesn't exist
Partials need to use local variables (they can't rely on #instance vars)
--
Partials
You'll be best doing this:
<%= render partial"statuses/comments", collection: #comments, as: comment %>
There is a little-known piece of functionality in Rails' partials which allows you to basically "reload" the partial for each member of a collection.
The reason this is important is because it cuts out a LOT of code from your partial. If you use the partial I posted above, you'll only need this code inside the partial:
#app/views/statuses/_comments.html.erb
<div class="com_con">
<%= Rinku.auto_link(comment.content).html_safe %>
</div>
If you set the correct #instance variable, and pass it into the collection option of the partial, Rails will basically reload the partial in a loop, like you have with the .each loop now
This will also work for singular items:
<%= render partial: "statuses/comments", object: #comment, as: comment %>
--
Instance Variable
The second issue is the setting of your instance variable
In your controller, you are not setting the #comments instance variable. This means you cannot load the contents of this variable into your view, consequently causing an issue like you've got
The way to fix this is very simple - use #instance variables you have set in your controller!
--
Escape
You may also need to look at how to escape quotes in your JS:
$("#comments_wrap").html("<%= escape_javascript(render :partial => \"statuses/comments\", :locals => {:comment => comment}) %>")
I'm not sure if this is applicable in this case, but I do know if you encapsulated quotes inside another set, you'll get errors from your JS

The answer above helped me solve this. Rendering the comments as a collection helped me render the partial through ajax and I also needed to define #comments in my create action in my comments_controller as well to ensure it doesn't render blank.

Related

Unpermitted parameters: :utf8, :authenticity_token - Rails 5.2 form_with

I'm ripping my hair out with this one. I am getting an unpermitted params on a form_with with a nested resource. I am using Rails 5.2.1 and Ruby 2.5.
I am not sure where in the world I am going wrong with this. I have tried all sorts of variations of site_params but to no luck. Any help would be appreciated.
Here's my routes.rb:
resources :locations do
post 'sites', to: 'sites#custom_create', as: :site_custom
resources :sites, except: [:edit, :update, :show]
end
And the relevant Controller Functions:
def new
verify_site_name or return
#site = #location.sites.new
authorize #site
#available_site = AvailableSite.find_by(site_name: params[:site_name])
#finder_results = get_finder_results([:site_name], #location)
end
def create
verify_site_name or return
#site = #location.sites.new(site_params)
authorize #site
respond_to do |format|
if #site.save
format.html { redirect_to location_sites_path, notice: 'Location was successfully created.' }
format.json { render :show, status: :created, site: #site }
else
format.html { redirect_to location_sites_path, alert: "#{#site.errors.full_messages.first}" }
format.json { render json: #site.errors, status: :unprocessable_entity }
end
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def site_params
params.permit(:location_id, :place_id, :site_name, :review_url)
end
# Use callbacks to share common setup or constraints between actions.
def set_site
#site = Site.find(params[:id])
end
def set_location
#location = Location.friendly.find(params[:location_id])
end
And of course, the form itself:
<%= form_with(model: [#location, #site], local: true, class: 'site-form') do |form| %>
<%= hidden_field_tag(:site_name, #available_site.site_name) %>
<div class="field md:w-3/4 lg:w-2/3 mx-auto text-left">
<%= form.text_field :review_url, class: 'text-input', placeholder: 'https://www.facebook.com/yourbusinessname/review/?ref=page_internal' %>
<span class="form-required">*required</span>
</div>
<%= form.submit "Manually Submit #{#available_site.site_name.titleize}", class: 'btn btn-green btn-outline' %>
<% end %>
And lastly, the log:
Started POST "/locations/tekamar-mortgages-ltd/sites" for 127.0.0.1 at 2018-12-03 15:30:57 +0000
Processing by SitesController#custom_create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"l/DjkUbVNyw+nrXxo1B/9IGru043Ftroxy8FcuNcZuxmJ7V3j0gC8njm5kpGPT8c7tMWSaAR/ler3cSHY+t8aA==", "site"=>{"site_name"=>"google", "review_url"=>"https://www.yelp.ca/biz/your-busines-sname?utm_campaign=www_business_share_popup&utm_medium=copy_link&utm_source=(direct)"}, "commit"=>"Create Site", "location_id"=>"tekamar-mortgages-ltd"}
Location Load (0.8ms) SELECT "locations".* FROM "locations" WHERE "locations"."slug" = $1 LIMIT $2 [["slug", "tekamar-mortgages-ltd"], ["LIMIT", 1]]
↳ app/controllers/sites_controller.rb:78
User Load (1.9ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
↳ /Users/richsmith/.rvm/gems/ruby-2.5.1/gems/activerecord-5.2.1/lib/active_record/log_subscriber.rb:98
Unpermitted parameters: :utf8, :authenticity_token, :site, :commit
Redirected to http://localhost:3000/locations/tekamar-mortgages-ltd/sites
Completed 302 Found in 13ms (ActiveRecord: 2.6ms)
Try:
def site_params
params.require(:site).permit(:location_id, :place_id, :site_name, :review_url)
end
Params for site are nested in params[:site]. You should first take this hash out of all the params, and then call permit on it. Right now you're sanitizing all the params (that include some stuff you're clearly not interested in, as utf8 or authenticity_token).

When attempting to create a new instance it's losing the associated parameter required to do so

Rails 5.1.6
I've got an app where products are listed and you can add a quantity of a product to an order. Well, that's the idea anyway. So, right now I've got a form to grab the quantity and also grab the product id and the order id to associate them through the order_items table which also holds the quantity. It looks like the form is grabbing the order_id and setting it in the order_items parameter. In this case, 5. Order with id 5 does exist in the db. When the params are passed to .new however, it's passing a blank id? What am I missing here?
ActiveRecord::RecordNotFound (Couldn't find Order with 'id'=): < wha?where'd the id go?
Form ERB
<% #products.each do |product| %>
<div class="col s4">
<h4><%= link_to product.name, product_path(product) %></h4>
<%= form_for #order_item do |f| %>
<%= f.hidden_field :order_id, value: #order.id %>
<%= f.hidden_field :product_id, value: product.id %>
<%= f.number_field :quantity, placeholder: "quantity" %>
<span class="waves-effect waves-light btn"><%= f.submit "Add to order" %></span>
<% end %>
</div>
class OrderItemsController < ApplicationController
def create
#order = Order.find(params[:id])
#item = #order.order_items.new(item_params)
#order.save
if #order.save
flash[:notice] = "Your order has been added!"
redirect_to orders_path
else
render :new
end
end
def item_params
params.require(:order_item).permit(:quantity, :product_id, :order_id)
end
Terminal
Started POST "/order_items" for 127.0.0.1 at 2018-06-06 16:50:31 -0700
Processing by OrderItemsController#create as JS
Parameters: {"utf8"=>"✓", "order_item"=>{"order_id"=>"5",
"product_id"=>"2", "quantity"=>""}, "commit"=>"Add to order"}
Order Load (0.2ms) SELECT "orders".* FROM "orders" WHERE
"orders"."id" = $1 LIMIT $2 [["id", nil], ["LIMIT", 1]]
Completed 404 Not Found in 2ms (ActiveRecord: 0.2ms)
ActiveRecord::RecordNotFound (Couldn't find Order with 'id'=):
app/controllers/order_items_controller.rb:4:in `create'
There are at least three things wrong with your :create action:
1) One of the hidden fields in your form passes the order_id in as a param, you should use that to find the order like so:
#order = Order.find(params[:order_item][:order_id])
2) You call save twice on the #order instance in the :create action.
3) You are actually calling save on the #order instance variable, but at no point do you save the #item instance variable. Is #item saved when #order is saved?
So I'd try the following:
def create
#order = Order.find(params[:order_item][:order_id])
# how come you don't save this? You instantiate it but don't appear to call save at any point.
#item = #order.order_items.new(item_params)
# remove the following line, which I've commented out:
# #order.save
# Consider whether you wish to save #order or #item, or both
if #order.save
flash[:notice] = "Your order has been added!"
redirect_to orders_path
else
render :new
end
end
Hope it helps, good luck
Here:
#order = Order.find(params[:id])
You're finding by params[:id]. But look!
Parameters: {"utf8"=>"✓", "order_item"=>{"order_id"=>"5", "product_id"=>"2", "quantity"=>""}, "commit"=>"Add to order"}
No params[:id]. You do, however, have params[:order_item][:order_id]. Perhaps you intended to use that?
Also, you can simplify your create action:
def create
#order_item = OrderItem.new(item_params)
if #order_item.save
flash[:notice] = "Your order has been added!"
redirect_to orders_path
else
render :new
end
end
Given that you have all the order_item attributes in your parameters:
"order_item"=>{"order_id"=>"5", "product_id"=>"2", "quantity"=>""}
There's no real need to find #order (unless you're feeling all belt and suspenders about things).

How to manually save a reference object in Rails

Edit: Main problem was that when I added the reference fields, I did theater:reference and not theater:references so the field was not marked as a foreign key. Once I undid those migrations and redid them correctly, I was able to make this work.
In my showtimes controller, I am trying to automatically set the theater id to whatever theater owns the screen that the user inputed, but when I try to save it as an integer or a string, I get an error. Yet, when I try to save it as a theater object, I get "Unpermitted parameter: theater" from the console and a "Theater must exist" error from the rails application.
showtimes_controller:
class ShowtimesController < ApplicationController
before_action :set_theater, only: [:create, :edit]
before_action :set_showtime, only: [:show, :edit, :update, :destroy]
# GET /showtimes
# GET /showtimes.json
def index
#showtimes = Showtime.all
end
# GET /showtimes/1
# GET /showtimes/1.json
def show
end
# GET /showtimes/new
def new
#showtime = Showtime.new
end
# GET /showtimes/1/edit
def edit
end
# POST /showtimes
# POST /showtimes.json
def create
#showtime = Showtime.new(showtime_params)
respond_to do |format|
if #showtime.save
format.html { redirect_to #showtime, notice: 'Showtime was successfully created.' }
format.json { render :show, status: :created, location: #showtime }
else
format.html { render :new }
format.json { render json: #showtime.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /showtimes/1
# PATCH/PUT /showtimes/1.json
def update
respond_to do |format|
if #showtime.update(showtime_params)
format.html { redirect_to #showtime, notice: 'Showtime was successfully updated.' }
format.json { render :show, status: :ok, location: #showtime }
else
format.html { render :edit }
format.json { render json: #showtime.errors, status: :unprocessable_entity }
end
end
end
# DELETE /showtimes/1
# DELETE /showtimes/1.json
def destroy
#showtime.destroy
respond_to do |format|
format.html { redirect_to showtimes_url, notice: 'Showtime was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_showtime
#showtime = Showtime.find(params[:id])
end
def set_theater
screenInfo = Screen.where("id = ?", params[:showtime][:screen])
params['showtime']['theater'] = Theater.find(screenInfo[0]['theater_id'])
end
# Never trust parameters from the scary internet, only allow the white list through.
def showtime_params
params.require(:showtime).permit(:date, :time, :archived, :movie_id, :theater, :screen)
end
end
showtimes model:
class Showtime < ApplicationRecord
belongs_to :movie
belongs_to :theater
end
Showtimes _form
<%= form_for(showtime) do |f| %>
<% if showtime.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(showtime.errors.count, "error") %> prohibited this showtime from being saved:</h2>
<ul>
<% showtime.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :date %>
<%= f.date_select :date %>
</div>
<div class="field">
<%= f.label :time %>
<%= f.time_select :time %>
</div>
<div class="field">
<%= f.label :archived %>
<%= f.check_box :archived %>
</div>
<div class="field">
<%= f.label :movie_id %>
<%= f.text_field :movie_id %>
</div>
<div class="field">
<%= f.label :screen %>
<%= f.text_field :screen %>
</div>
<%= f.hidden_field :theater, :value => "" %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Error when trying to save as integer:
Theater(#70015922237640) expected, got Fixnum(#11723820)
Error when trying to save as string:
Theater(#70015868755420) expected, got String(#11739240)
Logs when trying to save as Theater object:
Started POST "/showtimes" for IP at 2016-11-08 20:22:37 +0000
Processing by ShowtimesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"nENPV5d6YRXdcx3H+Xa9ZypGtyFlaTg+zyENGB10TmW9OyWxLR9Dsl7nDoG9irq+3qApiNA2/oEqL5RZ0SXorA==", "showtime"=>{"date(1i)"=>"2016", "date(2i)"=>"11", "date(3i)"=>"8", "time(1i)"=>"2016", "time(2i)"=>"11", "time(3i)"=>"8", "time(4i)"=>"20", "time(5i)"=>"22", "archived"=>"0", "movie_id"=>"2", "screen"=>"1", "theater"=>""}, "commit"=>"Create Showtime"}
[1m[36mScreen Load (0.3ms)[0m [1m[34mSELECT "screens".* FROM "screens" WHERE (id = '1')[0m
[1m[36mTheater Load (0.2ms)[0m [1m[34mSELECT "theaters".* FROM "theaters" WHERE "theaters"."id" = ? LIMIT ?[0m [["id", 1], ["LIMIT", 1]]
Unpermitted parameter: theater
[1m[35m (0.1ms)[0m [1m[36mbegin transaction[0m
[1m[36mMovie Load (0.2ms)[0m [1m[34mSELECT "movies".* FROM "movies" WHERE "movies"."id" = ? LIMIT ?[0m [["id", 2], ["LIMIT", 1]]
[1m[35m (0.2ms)[0m [1m[31mrollback transaction[0m
Rendering showtimes/new.html.erb within layouts/application
Rendered showtimes/_form.html.erb (13.6ms)
Rendered showtimes/new.html.erb within layouts/application (16.4ms)
Completed 200 OK in 323ms (Views: 86.5ms | ActiveRecord: 3.9ms)
How the hell do I save this parameter?
Have you tried assigning your object to an instance variable, and assigning it before saving?
On your before_action
def set_theater
#theather = ... # Code to find the theather
end
On your create action
def create
#showtime = Showtime.new(showtime_params)
#showtime.theather = #theather
... # Code to save and handle errors
end
You use theater instead of theater_id in several places in your code, and you'll need to change it in all the places, in order for this to work.
Firstly - you can't select a theater in our form... html doesn't recognise a type of theaterand will not pass one through - so your form needs to pass the theater_id instead (which will be an integer that it happily can deal with).
# eg here make sure it's a theater_id
<%= f.hidden_field :theater_id, :value => #theater.id %>
next - your require/permit is probably what's throwing some errors - you need that to be theater_id as well:
def showtime_params
params.require(:showtime).permit(:date, :time, :archived, :movie_id, :theater_id, :screen)
end
Now you need to fetch the theater out, using the screen-info param - but also keep in mind that this might come through as nil some times (so a guard-clause is always good):
def set_theater
if params[:showtime].present? && params[:showtime][:screen_id].present?
screen_info = Screen.find(params[:showtime][:screen_id])
#theater = Theater.find(screenInfo.theater_id)
end
end
Note: I have updated naming-schemes to be rail-standard and removed the thing where you try to set the theatre in params as below:
params['showtime']['theater'] = Theater.find(screenInfo[0]['theater_id'])
I don't know what you're actually trying to do with this line of code, but whatever it is, params doesn't work that way - consider that params is "the set of things that were passed through to us from the user, and are then thrown away" - we don't use it to store new values that we create ion the controller. That's what #variables are for
Can you explain more what you're trying to do and we'll figure out the right way to do it :)

Rails: Displaying a user post form_for on a user page with nested routes

I'm building a facebook clone, and I'm trying to have a text area on each user's page to allow them to make posts. I've tried a whole bunch of different things with no success, but right now I am getting this error when trying to access the user's show page:
First argument in form cannot contain nil or be empty
with this code:
Rails.application.routes.draw do
resources :friends, only: [:index, :destroy]
resources :posts
resources :friend_requests
devise_for :users
devise_scope :user do
root 'devise/sessions#new'
end
resources :users, only: [:index, :show] do
resources :posts
end
get 'about', to: 'static_pages#about'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
_post_form.html.erb
<%= form_for [#user, #post] do |f| %>
<%= f.text_area :content, size: "60x12", placeholder: "What do you want to say?" %>
<%= f.submit "Post" %>
<% end %>
class PostsController < ApplicationController
def index
#posts = Post.all
end
def new
#post = Post.new
#user = User.find(params[:user_id])
end
def create
#post = current_user.posts.build(post_params)
if #post.save
flash[:success] = "Posted!"
redirect_to user_path(current_user)
else
flash[:notice] = "Post could not be submitted"
redirect_to users_path
end
end
private
def post_params
params.require(:post).permit(:content)
end
end
class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
end
users/show.html.erb
<h4>You are signed in as <%= current_user.email %>! </h4>
<% if #user == current_user %>
<%= render "notifications" %>
<%= render 'shared/post_form' %>
<% end %>
<%= params.inspect %>
<%= current_user.id %>
server log:
Processing by UsersController#show as HTML
Parameters: {"id"=>"4"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 4], ["LIMIT", 1]]
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 4], ["LIMIT", 1]]
Rendering users/show.html.erb within layouts/application
FriendRequest Load (0.5ms) SELECT "friend_requests".* FROM "friend_requests" WHERE "friend_requests"."friend_id" = $1 ORDER BY "friend_requests"."id" ASC LIMIT $2 [["friend_id", 4], ["LIMIT", 1000]]
Rendered users/_notifications.html.erb (2.0ms)
Rendered shared/_post_form.html.erb (3.0ms)
Rendered users/show.html.erb within layouts/application (10.2ms)
Completed 500 Internal Server Error in 23ms (ActiveRecord: 1.3ms)
ActionView::Template::Error (First argument in form cannot contain nil or be empty):
1: <%= form_for [#user, #post] do |f| %>
2: <%= f.text_area :content, size: "60x12", placeholder: "What do you want to say?" %>
3: <%= f.submit "Post" %>
4: <% end %>
app/views/shared/_post_form.html.erb:1:in `_app_views_shared__post_form_html_erb___99030300856795657_70237723952000'
app/views/users/show.html.erb:5:in `_app_views_users_show_html_erb___3196827877852207953_70237724137160'
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 (6.7ms)
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 (5.0ms)
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.1ms)
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 (96.4ms)
You say that your form is having a problem rendering on the user's show page. If you have this form w/ nested resource setup like this:
form_for [#user, #post]
It means your form needs access to both the #user and the #post instance variable whereever the form is to be rendered. In this case, it is in the show action in your users controller. So your users controller should have something like this:
def show
#user = User.find(params[:id])
#post = #user.posts.build
end
I'm assuming your _post_form is loaded when you go to your posts#new route which is handled by this posts controller action:
def new
#post = Post.new
#user = User.find_by(id: params[:id])
end
Nested routes (in this case user > post) place the parent resource's id in the param resource_id, in you case it would be params[:user_id]. So, essentially, change this line:
#user = User.find_by(id: params[:id])
...to:
#user = User.find(params[:user_id])
That will access the correct id in the params and will cause an exception if no user was found (by using find instead of find_by), that will alert you to the any problem before you get to the view rendering. In your case the #user was nil and you got the form_for error you posted.
Update
I see from your logs you are going to the users#show action, which is this one:
def show
#user = User.find(params[:id])
end
as you can see, you're not setting the #post variable which you're passing to the form here:
form_for [#user, #post]
Add this to you action:
def show
#user = User.find(params[:id])
#post = Post.new
end

Model instances not flagged as changed after successful attribute update

I would like to do conditionally show/hide some elements in one of my views depending on if a #project.update changed attributes or not.
I am trying to understand WHY my model instances are not being marked as changed after a successful attribute update.
It appears that ActiveModel::Dirty is not properly indicating my model's attributes have changed or more likely I'm not using it properly.
Here is an annotated log of a PATCH request I make to my ProjectController#update action. In it you will see that the attributes change but the model instance does not reflect it. For what it's worth, the controller was generated by a Rails scaffold operation. There's nothing out of the ordinary.
#
# FORM SUBMITTED FROM BROWSER WITH A CHANGE TO THE ATTRIBUTE NAMED "title"
#
Started PATCH "/projects/2" for 127.0.0.1 at 2016-04-23 15:47:38 -0700
Processing by ProjectsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0JH/fEKx+Qk6mOY+eVTteKQUKrZUVXroKzMxuztrTzE/voI+PtzmQnJLGVM5bgdmzJyHDpAon3dzcvvjJ3yEtQ==", "project"=>{"title"=>"changed"}, "commit"=>"Update Project", "id"=>"2"}
Project Load (0.1ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
#
# DEBUGGER KICKS IN BEFORE THE UPDATE HAS HAPPENED
#
[40, 49] in app/controllers/projects_controller.rb
40:
41: # PATCH/PUT /projects/1
42: # PATCH/PUT /projects/1.json
43: def update
44: byebug
=> 45: respond_to do |format|
46: if #project.update(project_params)
47: format.html { redirect_to #project, notice: 'Project was successfully updated.' }
48: format.json { render :show, status: :ok, location: #project }
49: else
#
# PROJECT TITLE IS STILL UNMOLESTED
#
(byebug) #project
<Project id: 2, title: "ORIGINAL_TITLE", created_at: "2016-04-23 22:47:30", updated_at: "2016-04-23 22:47:30">
# PROVE PARAMS CONTAIN A CHANGED ATTRIBUTE
(byebug) project_params
<ActionController::Parameters {"title"=>"changed"} permitted: true>
#
# TRIGGER UPDATE AND PERSIST NEW TITLE
#
(byebug) #project.update(project_params)
(0.2ms) begin transaction
SQL (0.9ms) UPDATE "projects" SET "title" = ?, "updated_at" = ? WHERE "projects"."id" = ? [["title", "changed"], ["updated_at", 2016-04-23 22:48:13 UTC], ["id", 2]]
(3.5ms) commit transaction
true
#
# WAT?
#
(byebug) #project.changes
{}
(byebug) #project.changed?
false
(bye bug)
Here is my ProjectsController#update action (standard Rails scaffold):
# app/controllers/projects_controller.rb
# PATCH/PUT /projects/1
# PATCH/PUT /projects/1.json
def update
byebug
respond_to do |format|
if #project.update(project_params)
format.html { redirect_to #project, notice: 'Project was successfully updated.' }
format.json { render :show, status: :ok, location: #project }
else
format.html { render :edit }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
The corresponding view form (also from generated scaffolding):
# app/views/projects/_form.html.erb
<%= form_for(project) do |f| %>
<% if project.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(project.errors.count, "error") %> prohibited this project from being saved:</h2>
<ul>
<% project.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
It seems like you are trying to achieve something if there were any changes made during an update.
If that's the case, you could do something like this :
Use a after_save or after_update callback as necessary for the model and within your callback, if you check self.changes or self.changed? you'd get expected results.

Resources