Couldn't find Post without an ID using rails 4 - ruby-on-rails

guys i am suffering from a problem from last two days and i dont know whats going wrong with my code. I have two model with the name of 'post' and 'descrip'. Descrip belongs_to post as post has_one descrip. So when i submit form for post then next form appear which is for descrip.I descrip form i have one hidden field to pass post_id. But when i submit descrip form an error appear that "POST can't be find without an id". Here below my code as
in view
<%= form_for :descrip, url:{action: "create", :controller => "descriptions"} do |f| %>
<li>
<%= f.label 'Detail' %><br>
<%= f.text_field :detail %>
</li>
<li>
<%= f.hidden_field :post_id , :value => #post.id %>
</li>
<li>
<%= f.submit %>
</li>
<% end %>
In Descriptions_controller
def new
#descrip = Descrip.new
end
def create
#post = Post.find(params[:descrip][:post_id])
#descrip = #post.descrips.build(descrip_params)
if #descrip.save
render #post
else
render 'new'
end
end
model of post and descrip
class Post < ActiveRecord::Base
has_one :descrip, :dependent => :destroy
end
class Descrip < ActiveRecord::Base
belongs_to :post
end
resources.rb
resources :descriptions
get "descriptions/new", :to => "descriptions#new", as: :descriptions_new
post "descriptions/create/:id", :to => "descriptions#create", as::descriptions_create
resources :posts do
resources :descriptions
end
Kindly suggest me what i should do.How i can solve my error and how i can get post_id in my decrips table.Please.

It seems like there are two possibilities.
1) Firstly, it could be that your params are not what you think they are and plugging in an invalid number for Post.find(). Could you share what your params looks like?
2) If that's not the case you could be calling id on a post that isn't yet saved and therefore can't be found by ActiveRecord within your database. If you're submitting this form along with a form to create a post, you're likely saving the description first. Make sure your post either exists in the database or is saved before the description to fix this.
Out of curiosity is there any reason you've made description a separate table from post? It seems like you could save yourself a lot of trouble just having it be a text column within the posts table.

in your action add logger.info:
def create
logger.info "---params ==> #{params.inspect}---"
#post = Post.find(params[:descrip][:post_id])
#descrip = #post.descrips.build(descrip_params)
if #descrip.save
render #post
else
render 'new'
end
end
run the application then in log/development.rb file you can view the all params value.
if params or not passing try with
<%= hidden_field_tag 'descrip[post_id]', #post.id %>

Related

Creating form_for for model association

I have 2 models:
brand
has_many :products
product
belongs_to :brand
In my view (show_brand.html.erb), i displaying all information about brand using #brand.name ....
I want to create form for product that belongs_to brand i'm displaying information about.
Something like:
form_for(#brand.products) ...
How can i preform that?
How can i attach user_id to product form (product belongs_to user) without adding it in controller manually
NOTICE:
About first item in my list, i know that it can be done by upgrading routes to nested and passing array with main object and association object. But if there is another way of doing that? Without modifying routes.rb and ...
You can use accepts_nested_attributes_for.
#brand_controller.rb
def new
#brand = Brand.new
#product = #brand.products.build
end
def create
#brand = Brand.new(brand_params)
if #brand.save
.....
else
.....
end
end
private
def brand_params
params.require(:brand).permit(:id, brand_attribute_1, brand_attribute_2, products_attributes: [:id, :product_attribute_1, :user_id, :product_attribute_2])
end
In your form
<%= form_for #brand do |f| %>
----code for brand attributes ---
<%= f.fields_for #product do |p| %>
----code for product attributes----
<%= p.hidden_field user_id, :value => current_user.id %> #to attach user_id to product
<% end %>
<%= f.submit "Submit" %>
<% end %>
For question 1, you can use "nested form".
Please check below link.
http://railscasts.com/episodes/196-nested-model-form-part-1?view=asciicast
For question 2, even though you set user_id in "product form", you still have to do some check in your controller/model in case any undesired value is set to user_id. So the better way is you set it yourself at backend.

How to use simple form for comments from a nested resource?

So I'm creating a blog rails app and I'm trying to create a comment session on the blog. I'm trying to render a form using simple form, but I'm having a hard time getting the simple form to work. For now I have:
<%= simple_form_for ([#user, #post.comments.build]) do |f| %>
<%= f.input :comment %>
<%= f.button :submit %>
<% end %>
but it says that post.comments isn't a defined path.
My comment model:
class Comment < ActiveRecord::Base
belongs_to :post
belongs_to :user
end
post belongs to user and has_many comments
user has many post and has many comments
Here are my current routes:
resources :posts do
resources :comments
end
Any advice?
Thanks!
Why are you sending #user in simple_form_for?
Use #post in place of #user.
I found a fix to this by generating a migration for the comment. I just had to make sure that everything with an association actually had the columns in the database. After that I just made sure I was rendering the #post.comment instead of comment/comment. Hope this helps anyone that came across the same problem.
remove user from the form.
<%= simple_form_for [#post, #post.comments.build] do |f| %>
<%= f.input :comment %>
<%= f.button :submit %>
<% end %>
and then you will assign the user value in the controller using something like current_user if you are using devise.
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(comment_params)
#comment.user = current_user
#comment.save
redirect_to #post
end
def comment_params
params.require(:comment).permit(:comment)
end
it's a bad idea to have a model named comment and a field into it named comment. I would prefer to call it content

has_many Custom Create Action

I think I need to user :through somewhere in my associations, but im very new to this so any help would be appreciated.
For simplicity, lets say I have 3 models.
Faults
Users
FaultComments
Where
Faults - belong_to :user and has_many :fault_comments
Users - has_many :faults and has_many :fault_comments
FaultComments - belongs_to :fault and belongs_to: user
What i would like to do is the ability to add fault comments from the fault show page, currently I have the below but i cant get it all to work as it should.
routes.rb
devise_for :users do
get '/users/sign_out' => 'devise/sessions#destroy'
end
resources :faults
resources :fault_comments
views/faults/show.html.erb
<h3>Add New</h3>
<%= form_for #faultcomment, :url => fault_comments_path(:fault_id => #fault.id, :user_id => current_user.id) do |f| %>
<%= f.text_field :comment %>
<%= f.submit %>
<% end %>
controllers/faults_comments_controller.rb
def create
#fault = Fault.find(params[:fault_id])
#faultcomment = #fault.fault_comments.new(params[:faultcomment])
#faultcomment.user_id = params[:user_id]
#faultcomment.comment = :comment
if #faultcomment.save
redirect_to faults_path
end
end
First of all, I think you should probably leave the FaultCommentsController like it came, which was probably something like this:
def create
#fault_comment = FaultComment.new(params[:fault_comment])
#fault_comment.user = current_user
if #fault_comment.save
redirect_to faults_path
end
end
(As a side note, it would probably be worth your while to learn about CamelCase and snake_case and how to properly translate between the two. The snake_case corollary to FaultComment is fault_comment, not faultcomment. You will certainly run into problems if you don't understand this.)
Your form on views/faults/show.html.erb looks more or less right to me. If you change your controller back to the original, does it work?
Also, change your form like this:
<h3>Add New</h3>
<%= form_for #fault_comment, :url => fault_comments_path do |f| %>
<%= f.text_field :comment %>
<%= f.hidden_field :fault_id, #fault.id %>
<%= f.submit %>
<% end %>

nested resources and build method for making association

I have three models associated between: User, Post, Comment. Comment is nested resource with Post.
routes.rb
resources :posts do
resources :comments
end
User model:
has_many :comments
Post model:
has_many :comments
Comment model:
belonsg_to :user
belonsg_to :post
The goal is when User makes new Comment it creates association with that user. So you can see it like User knows all comments he has made.
comments_controller.rb
def create
#post = Post.find(params[post_id]
#comment = #post.comments.build[:comment]
current_user.comments >> #comment
....
end
new.html.erb
<% form_for [#post, #post.comment.build] do |f| %>
.....
<% end %>
This gives me an error no method comments. What should I make to avoid this?
Most likely you are missing "S" letter in new.html.erb. Should be comments:
<% form_for [#post, #post.comments.build] do |f| %>
.....
<% end %>
If there is some more logic behind you didn't post let us know. Your create action looks fine. Try to look in console student_id attribute, if its populated with ID than you are fine.cheers.
Use
#post.comments.build
Instead of
#post.comment.build (x)
this should work, if possible move this line of code from view to controller
for more info
http://guides.rubyonrails.org/association_basics.html#detailed-association-reference
In new.html.erb file, you are using "s" for build method.
It should be,
<% form_for [#post, #post.comments.build] do |f| %>
.....
<% end %>

How to get Rails build and fields_for to create only a new record and not include existing?

I am using build, fields_for, and accepts_nested_attributes_for to create a new registration note on the same form as a new registration (has many registration notes). Great.
Problem: On the edit form for the existing registration, I want another new registration note to be created, but I don't want to see a field for each of the existing registration notes.
I have this
class Registration < ActiveRecord::Base
attr_accessible :foo, :bar, :registration_notes_attributes
has_many :registration_notes
accepts_nested_attributes_for :registration_notes
end
and this
class RegistrationsController < ApplicationController
def edit
#registration = Registration.find(params[:id])
#registration.registration_notes.build
end
end
and in the view I am doing this:
<%= form_for #registration do |r| %>
<%= r.text_field :foo %>
<%= r.text_field :bar %>
<%= r.fields_for :registration_notes do |n| %>
<%= n.text_area :content %>
<% end %>
<% end %>
and it is creating a blank text area for a new registration note (good) and each existing registration note for that registration (no thank you).
Is there a way to only create a new note for that registration and leave the existing ones alone?
EDIT: My previous answer (see below) was bugging me because it's not very nice (it still loops through all the other registration_notes needlessly). After reading the API a bit more, the best way to get the behaviour the OP wanted is to replace:
<%= r.fields_for :registration_notes do |n| %>
with:
<%= r.fields_for :registration_notes, #registration.registration_notes.build do |n| %>
fields_for optionally takes a second parameter which is the specific object to pass to the builder (see the API), which is built inline. It's probably actually better to create and pass the new note in the controller instead of in the form though (just to move the logic out of the view).
Original answer (I was so close):
Just to clarify, you want your edit form to include a new nested registration note (and ignore any other existing ones)? I haven't tested this, but you should be able to do so by replacing:
<%= r.fields_for :registration_notes do |n| %>
with:
<%= r.fields_for #registration.registration_notes.build do |n| %>
EDIT: Okay, from a quick test of my own that doesn't work, but instead you can do:
<%= r.fields_for :registration_notes do |n| %>
<%= n.text_area :content if n.object.id.nil? %>
<% end %>
This will only add the text area if the id of the registration note is nil (ie. it hasn't been saved yet).
Also, I actually tested this first and it does work ;)
If you want to create a new registration form on your edit action, you can just instantiate a new registration_note object. Right now, your form is for the existing registration object.
I believe this is what you want:
class RegistrationsController < ApplicationController
def edit
#new_registration_note = RegistrationNote.new
#registration = Registration.find(params[:id])
#registration.registration_notes.build
end
end
In your view, you should pass a hidden param that references the registration record id:
<%= form_for #new_registration_note do |r| %>
<%= r.hidden_field :registration_id, :value => #registration.id %>
<%= r.text_area :content %>
<% end %>
Now, you can create your new registration note that belongs to #registration. Make sure you have a column in your registration_notes table to point to the registration. You can read more about associations here: http://guides.rubyonrails.org/association_basics.html
Thank you so much for your help as I said in my post the only problem with the approach from "Zaid Crouch"(I don't know how to make a reference to a user hehe) is that if the form has error fields the form will be clear and boom after the page reloading you'll have nothing filled in your form and can you imagine if you form is like 20 or 30 fields that would be a terrible user experience of course
Here is my solution that works with validation models:
class Registration < ActiveRecord::Base
attr_accessible :foo, :bar, :registration_notes_attributes
has_many :registration_notes
has_one :new_registration, class_name: 'RegistrationNote'
accepts_nested_attributes_for :new_registration
end
class RegistrationsController < ApplicationController
def edit
#registration = Registration.find(params[:id])
#registration.build_new_registration
end
end
<%= form_for #registration do |r| %>
<%= r.text_field :foo %>
<%= r.text_field :bar %>
<%= r.fields_for :new_registration do |n| %>
<%= n.text_area :content %>
<% end %>
<% end %>
I'm using simple_form in my example if you want to see the same working with validations and transaction take a look at the complete post here:
http://elh.mx/ruby/using-simple_form-for-nested-attributes-models-in-a-has_many-relation-for-only-new-records/
As Heriberto Perez correctly pointed out the solution in the most upvoted answer will simply discard everything if there's a validation error on one of the fields.
My approach is similar to Heriberto's but nevertheless a bit different:
Model:
class Registration < ActiveRecord::Base
has_many :registration_notes
accepts_nested_attributes_for :registration_notes
# Because 0 is never 1 this association will never return any records.
# Above all this association don't return any existing persisted records.
has_many :new_registration_notes, -> { where('0 = 1') }
, class_name: 'RegistrationNote'
accepts_nested_attributes_for :new_registration_notes
end
Controller:
class RegistrationsController < ApplicationController
before_action :set_registration
def edit
#registration.new_registration_notes.build
end
private
def set_registration
#registration = Registration.find(params[:id])
end
def new_registration_params
params.require(:registration).permit(new_registrations_attributes: [:content])
end
end
View:
<%= form_for #registration do |r| %>
<%= r.text_field :foo %>
<%= r.text_field :bar %>
<%= r.fields_for :new_registration_notes do |n| %>
<%= n.text_area :content %>
<% end %>
<% end %>

Resources