Rails Saving User Selected Foreign Key In Form - ruby-on-rails

I am newbie to Rails and I have been struggling with this idea that just can't get over my head. For example I have
class Survey < ActiveRecord::Base
has_many :questions
end
class Question < ActiveRecord::Base
belongs_to :survey
end
I have created a set of surveys. Now I want to create some questions and assign it to the survey through its foreign key survey_id. In the Question new.html.erb page, I used advanced form to show the Survey ID(I followed this tutorial). It works fine however, when I click submit, it seems like the survey_id doesn't save.
This is my question_controller.rb
def create
#question = Question.create(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
else
format.html { render :new }
end
end
def question_params
params.require(:question).permit(:description, :date_created, :survey_id)
end
Here is the form:
<%= form_for(#question) do |f| %>
<div class="field">
<%= f.label :survey_id %><br>
<%= collection_select(:question, :survey_id, Survey.all, :id, :description, prompt: true ) %>
</div>
<% end %>
I know in order for this to work, I have to do something like
#question = #survey.questions.create(...)
but I have no idea how to get the #survey instance before the user click on the drop down and select the appropriate survey.
Anyone has any idea on how to do this ??

Your create method should be
def create
#survey = Survey.find(params[:survey_id])
#question = #survey.questions.create(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
else
format.html { render :new }
end
end
or you can also use filter
class QuestionsController < ApplicationController
before_filter :set_survey, only: :create
def create
#question = #survey.questions.create(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
else
format.html { render :new }
end
end
private
def set_survey
#survey = Survey.find(params[:survey_id]) || Survey.new
end
end

you have survey objects created and you want them to be associated to questions,
so, on your question's form if you are using select drop-down with survey names to select from then set select options values to survey id. so your question params will contain survey_id parameter with value equal to selected survey's id. and thus Question.create(question_params) will create question with survey_id.

Related

Creating a nested resource in Rails 5

I am trying to create a nested resource so that products can have notes associated with them. I have set up the associations within the model etc, but when I try to use the form to create a new note, I get the following error:
NoMethodError in Notes#create
Showing /Users/myusername/myapp/app/views/notes/_form.html.erb where line #2 raised:
undefined method `notes_path' for #<#<Class:0x00007fb3630b1ad0>:0x00007fb361eab868>
This is the line it is referring to:
<%= simple_form_for [#product, #note] do |f| %>
This are the new & create actions in the notes controller:
def new
#product = Product.find(params[:product_id])
#note = #product.notes.build
end
def create
#note = Note.new(product: #product)
respond_to do |format|
if #note.save
format.html { redirect_to product_notes, notice: 'Note was successfully created.' }
else
flash.now[:error] = "It doesnt work"
render 'new'
end
end
end
and the form partial:
<%= simple_form_for [#product, #note] do |f| %>
<%= f.error_notification %>
<%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
<div class="form-inputs">
<%= f.input :content %>
<%= f.input :author %>
<%= f.check_box :visible %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
I am going round in circles with making changes, and cannot seem to find any documentation on nested resources that isn't deprecated. Can anybody assist, please?
Edited to add:
I changed my controller action to something based on PGill's answer and can now get the page to load without an action controller error. However, it now re-renders the new note form, with errors saying that the form fields cannot be blank. They were not blank when I submitted them - what's happening to cause this?
Updated controller action:
def create
#product = Product.find(params[:product_id])
#note = #product.notes.new
respond_to do |format|
if #note.save
format.html { redirect_to product_notes_path(#product), notice: 'Note was successfully created.' }
else
format.html { render :new, notice: 'Note failed to be created.' }
end
end
end
When I was previously getting errors, it had this as the request parameters, so they are getting passed?
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"lotsofletters",
"note"=>{"content"=>"test", "author"=>"test", "visible"=>"0"},
"commit"=>"Create Note",
"product_id"=>"1"}
Referring to your edit; of course you should get empty fields errors because you are creating a new object #note without providing any attributes for it:
#note = #product.notes.new
it should be like
#note = #product.notes.build(params[:note])
also take care to provide a sanitizer for note in notes controller :
private
def note_params
params.require(:note).permit(:content, :author, :visible, :product_id)
end
so your code in create will look like:
def create
#product = Product.find(params[:product_id])
#note = #product.notes.build(note_params)
respond_to do |format|
if #note.save
format.html { redirect_to product_notes_path(#product), notice: 'Note was successfully created.' }
else
flash.now[:error] = "It doesnt work"
render 'new'
end
end
end
private
def note_params
params.require(:note).permit(:content, :author, :visible, :product_id)
end
#product is nil in create
Your form is failing validations and rendering new
update the create action to
def create
#product = Product.find(params[:product_id])
#note = #product.notes.new
respond_to do |format|
if #note.save
format.html { redirect_to product_notes_path(#product), notice: 'Note was successfully created.' }
else
flash.now[:error] = "It doesnt work"
render 'new'
end
end
end
redirect_to should be product_notes_path(#product) notes#index

ActionController::UrlGenerationError in Comments#edit - Rails 4.0

I am using a ruby on rails blog tutorial and everytime I try to edit a comment I get an error.
Error: No route matches missing required keys: [:id].
Please help I am new to this.
Error found around line 3.
<h1>Editing comment</h1>
3. <%= form_for([:post, #comment]) do |f| %>
4. <div class="field">
5. <%= f.label :name %>
<%= f.text_field :name %>
Here is my routes.rb file code
Rails.application.routes.draw do
resources :posts do
resources :comments
end
end
My Comments_controller.rb code
class CommentsController < ApplicationController
# GET /comments
# GET /comments.json
def index
#comments = Comment.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #comments }
end
end
# GET /comments/1
# GET /comments/1.json
def show
#comment = Comment.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #comment }
end
end
# GET /comments/new
# GET /comments/new.json
def new
#comment = Comment.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #comment }
end
end
# GET /comments/1/edit
def edit
#comment = Comment.find(params[:id])
end
# POST /comments
# POST /comments.json
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to #post, notice: 'Comment was successfully created.' }
format.json { render json: #post, status: :created, location: #comment }
else
format.html { render action: "new" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PUT /comments/1
# PUT /comments/1.json
def update
#comment = Comment.find(params[:id])
#post = #comment.post
respond_to do |format|
if #comment.update_attributes(params[:comment])
format.html { redirect_to #post, notice: 'Comment was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
#comment = Comment.find(params[:id])
#post = Post.find(params[:post_id])
#comment.destroy
respond_to do |format|
format.html { redirect_to #post, notice: 'Comment was successfully deleted!' }
format.json { head :no_content }
end
end
def comment_params
params.require(:comment).permit(:post_id, :name, :email, :body)
end
end
So, to leave the comments alone, let me try to explain what I think it is your problem.
In your routes file you have nested resources, which means that this:
resources :posts do
resources :comments
end
end
are what is called nested resources, and this means that you have routes like:
posts/:post_id
posts/:post_id/comments/:comment_id
which you can see if you run rake routes.
This also means that the first route will call an action on your PostsController and the second route will call an action on your CommentsController.
So what I suggested you to do in your controller was to, first, render the form as [#post, #comment], which will tell the form_for helper to use your nested resource as the 'path to send the form'.
For this form to call your edit method you'll need to say that you want the form to be submitted there. This is done by the options for the form_for helper (http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html) and this is necessary because rails loves/is! RESTfull, and under this, the same route might have multiple behaviours depending on the HTTP verb/method you use.
So, have attention to this that I mentioned above, and you can probably guess what you are doing wrong.
As a last hint, your controller has this:
# GET /comments/1/edit
def edit
#comment = Comment.find(params[:id])
end
And this method renders this(I assume):
<h1>Editing comment</h1>
<%# I already fixed the form_for here %>
<%= form_for([#post, #comment]) do |f| %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
<% end %>
This form, since is rendered by the edit action, will (probably) be submitted to the update action. This update action is under /posts/:post_id/comments/:comment_id, and can be called using the PATCH(rails 4.0) verb. So your form_for needs, first, to have a post assigned to the variable #post, which should be passed by its controller. Second, it needs to go to the right route.
Here you are lucky since Rails is smart enough to see if what you're submitting is a new_record? and then its form_for will point to create or, if not, will point to update.
So all you need to do now, is to assign the right Post to #post and you are probably good to go.
Let me know if this worked for you.

Show username when posting comments in Rails

I have an app when users post album reviews called Pins. I created a comments model for other users to comment on the reviews. I'm struggling getting the comments to say "Posted by" and then show the user's name who posts them. Here is some of the code:
The pins model has_many :comments
The user model has_many :comments
The comments model belongs_to :pin
belongs_to :user
Here's the comments controller:
def create
#pin = Pin.find(params[:pin_id])
#comment = #pin.comments.create(params[:comment])
#comment.username = current_user
respond_to do |format|
if #comment.save
format.html { redirect_to #pin, 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
Here is the app as it is now:
http://powerful-reaches-7038.herokuapp.com
I've tried some of the other answers posted on Stack Overflow, but no dice. I'm trying to say something like:
<strong>Posted <%= time_ago_in_words(comment.created_at) %> ago by <%= comment.user.name %></strong>
You are assigning a User instance to the username field for the Comment. I assume that the username attribute is a string in the database. So if you want the name to appear in the comment then you need to assign it the name from the current user.
So:
#comment.username = current_user.name
If you already have an association between Comment and User then you could do:
#comment.user = current_user
<%= #comment.user.name %>
You save the username in
#comment.username = current_user
and show it with:
<%= comment.user.name %>
but it have to be
<%= comment.username %>

How to hookup validations for a mongoid embedded resource

I have a comments model embedded in a posts model:
class Post
include Mongoid::Document
field :name, :type => String
field :content, :type => String
embeds_many :comments
end
class Comment
include Mongoid::Document
field :content, :type => String
validates_presence_of :content
embedded_in :post, :inverse_of => :comments
end
The comment form, as expected, is included in posts/show:
p#notice = notice
h2= #post.name
p= #post.content
a.btn href=edit_post_path(#post) Edit
h3 New comment
= simple_form_for [#post, Comment.new] do |f|
= f.error_notification
= f.input :content, :as => :text
= f.button :submit
And in my comments controller:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to #post, notice: 'Comment created.' }
else
format.html { render :template => "posts/show" }
end
end
end
This seems to work for valid comments, but has two problems for blank comments. First, no validation message is shown. Second, the blank comment is rendered in the post/show template because it is included in #post (even though it isn't persisted) after calling #comment = #post.comments.build(params[:comment]).
The railscast on this topic uses #post.comments.create!(params[:comment]) instead of build, but this leads to an exception on any validation failure which I don't think is appropriate.
I could get around the second problem by refetching the post, but this seems kludgy:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to #post, notice: 'Comment created.' }
else
#post = Post.find(params[:post_id])
format.html { render :template => "posts/show" }
end
end
end
And even still, the validation is missing.
Does anyone have a suggestion for how this could be done better?

User and associated Post

I created an twiiter like app, where friends can post, but i want a include the name of the person who created the post in the list showing all the post.
here is my code
class PostsController < ApplicationController
def index
#posts = Post.all(:order => "created_at DESC")
respond_to do |format|
format.html
end
end
def create
#post = Post.create(:message => params[:message])
respond_to do |format|
if #post.save
format.html { redirect_to posts_path }
format.js
else
flash[:notice] = "Message failed to save."
format.html { redirect_to posts_path }
end
end
end
end
`
Assuming, of course, that the 'user has many posts' association is set, and the user model has a 'username' field, you can do this in your view :
<% #posts.each do |post| %>
<%= post.user.username %>
<% end %>

Resources