I'm developing a web in ror and I tried to ajaxing the comments.
The web has brands and products with comments. I tried first to ajaxing the brand's comments.
The brand's model
class Brand < ActiveRecord::Base
attr_accessible :name
has_many :products, :dependent => :destroy
has_many :comments, :dependent => :destroy
validates :name, :presence => true
end
The comment's model
class Comment < ActiveRecord::Base
attr_accessible :body, :brand_id, :product_id, :user_id
belongs_to :brand
belongs_to :product
validates :brand, :presence => {:unless => :product_id?, :message => "The comment must belongs to a brand or product"}
validates :product, :presence => {:unless => :brand_id?, :message => "The comment must belongs to a brand or product"}
validates :body, :presence => true
end
The comments controller Create
def create
#comment = Comment.new(params[:comment])
#brand = Brand.find(params[:comment][:brand_id])
respond_to do |format|
if #comment.save
#comments = #comment.brand.comments
format.html { redirect_to #brand, notice: 'Comment was successfully created.' }
format.json { render json: #comment, status: :created, location: #comment }
format.js { render #brand}
else
format.html { render action: "new" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
views/brands/_comments
<div class="well">
<%= simple_format comments.body %>
<%= link_to 'Edit', edit_comment_path(comments), :class => 'btn btn-mini btn-success' %>
<%= link_to 'Destroy', comment_path(comments), :method => :delete, :data => {:confirm => 'Are you sure?'}, :class => 'btn btn-mini btn-danger' %>
</div>
views/comments/create.js.rjs
$("#comments").html("<%= escape_javascript(render :partial => "comments", :collections => #comments) %>");
views/brand/show
<h2>Comments</h2>
<div id="comments">
<%= render :partial => "comments", :collection => #comments %>
</div>
<p></p>
<div id="comment-form">
<%= form_for #comment, :remote => true do |f| %>
<%= f.hidden_field :brand_id %>
<div class="field">
<%= f.text_area :body, :size => "25x5"%>
</div>
<div class="field">
<%= f.submit 'Enviar comentario', :class => 'btn btn-success' %>
</div>
<% end %>
</div>
But when I create a new product, the page was reload.
Really Thank you!
Related
Apologies in advance if this is a stupid question. I am learning Rails from scratch, so thanks for bearing with me.
So, I have a 'Person' model, shown below
class Person < ActiveRecord::Base
belongs_to :team
has_and_belongs_to_many :events, through: :event_people
validates :first_name, presence: true, length: { maximum: 255 }
validates :last_name, presence: true, length: { maximum: 255 }
validates :email, presence: true, length: { maximum: 255 }
end
and have created a form to create a new person, with associated team ID
<h1>Add new person</h1>
<div class="row">
<div class="col-md-8">
<%= form_with url: new_person_path do |person| %>
<div class="form-group">
<%= person.label :first_name %>
<%= person.text_field :name, id: :person_first_name, class:"form-control" %>
</div>
<div class="form-group">
<%= person.label :last_name %>
<%= person.text_field :name, id: :person_last_name, class:"form-control" %>
</div>
<div class="form-group">
<%= person.label :email %>
<%= person.text_field :email, id: :person_email, class:"form-control" %>
</div>
<div class="form-group">
<%= person.label :job_title %>
<%= person.text_field :job_title, id: :person_job_title, class:"form-control" %>
</div>
<div class="form-group">
<% #teams = Team.all %>
<%= person.label :team %>
<%= person.select(:team_id, #teams.collect{|a| [a.name, a.id]}, { include_blank: true }, {:class => "form-control"}) %>
</div>
<div class="actions">
<%= person.submit 'Submit button', {:class => 'btn btn-primary'}%>
</div>
<% end %>
</div>
</div>
and my routes.rb file is set up like this:
Rails.application.routes.draw do
resources :people
resources :teams
resources :organisations
resources :events
end
But whenever I submit the form to create a new person, I get the following error in the console:
POST http://localhost:3000/people/new 404 (Not Found)
Event though the relevant methods exist in my people_controller.rb:
class PeopleController < ApplicationController
def index
#people = Person.all
end
def show
#people = Person.find(params[:id])
end
def new
#people = Person.new
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #people }
end
end
def create
#people = Person.new(params[:person])
respond_to do |format|
if #people.save
format.html { redirect_to(#people,
:notice => 'Person was successfully created.') }
format.json { render :json => #people,
:status => :created, :location => #people }
else
format.html { render :action => "new" }
format.json { render :json => #people.errors,
:status => :unprocessable_entity }
end
end
end
Can anyone suggest what I might be doing wrong?
When you have an underlying model you will want to use <%= form_with model: #people do |person| %>
Reference: http://api.rubyonrails.org/v5.1/classes/ActionView/Helpers/FormHelper.html#method-i-form_with
You are posting to a method which, at least as far as I can tell, is supposed to output an empty form for entering attributes of your person.
Try a GET first, which would be in keeping with the rails interpretation of is REST URLs. Likely, the correct route also has no /new at the end.
Next, try rails routes to list all available routes.
By the way, if in development, rails should give you a meaningful, large help page, likely including available routes. Check your development.rb for some flag to enable that.
I'm making a task for a job. Rails 4 app where users can create posters. Posters can have multiple images to upload. Actually, I have no explicit errors, just two questions. But before questions, here are my files. Poster.rb:
class Poster < ActiveRecord::Base
has_many :poster_images, dependent: :destroy
accepts_nested_attributes_for :poster_images, allow_destroy: true
belongs_to :type
belongs_to :user
default_scope -> { order('created_at DESC') }
validates :title, :body, :publish_date, :user_id, :presence => true
end
poster_image.rb:
class PosterImage < ActiveRecord::Base
belongs_to :poster
has_attached_file :image, :styles => {:medium => "300x300>", :thumb => "100x100>" }
end
posters_controller.rb:
class PostersController < ApplicationController
before_filter :set_poster, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!, :except => [:index, :show]
authorize_resource
load_resource except: :create
# GET /posters
# GET /posters.json
def index
#posters = Poster.paginate(page: params[:page], :per_page => 10)
end
# GET /posters/1
# GET /posters/1.json
def show
end
# GET /posters/new
def new
end
# GET /posters/1/edit
def edit
end
# POST /posters
# POST /posters.json
def create
#poster = Poster.new(poster_params)
#poster.user_id = current_user.id
respond_to do |format|
if #poster.save
format.html { redirect_to #poster, notice: 'Poster was successfully created.' }
format.json { render action: 'show', status: :created, location: #poster }
else
format.html { render action: 'new' }
format.json { render json: #poster.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posters/1
# PATCH/PUT /posters/1.json
def update
respond_to do |format|
if #poster.update(poster_params)
format.html { redirect_to #poster, notice: 'Poster was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #poster.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posters/1
# DELETE /posters/1.json
def destroy
#poster.destroy
respond_to do |format|
format.html { redirect_to posters_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_poster
#poster = Poster.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def poster_params
params.require(:poster).permit(:title, :body, :publish_date, :type_id, :type_name, poster_images_attributes: :image )
end
end
_form.html.erb:
<%= simple_nested_form_for #poster, :html => {:multipart => true } do |f| %>
<%= f.input :title, :autofocus => true %>
<%= f.input :body %>
<%= f.input :publish_date %>
<%= f.input :type_id, :collection => Type.all, required: true %>
<%= f.fields_for :poster_images do |images_f| %>
<%= images_f.file_field :image %>
<%= images_f.link_to_remove "X" %>
<% end %>
<%= f.link_to_add "Add image", :poster_images %>
<div class="form-actions">
<%= f.button :submit, :class => 'btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
posters_path, :class => 'btn' %>
</div>
<% end %>
show.html.erb:
<%- model_class = Poster -%>
<div class="page-header">
<h1><%=t '.title', :default => model_class.model_name.human.titleize %></h1>
</div>
<dl class="dl-horizontal">
<dd><h3><%= #poster.title %></h3></dd>
<dd><%= #poster.body %></dd>
<dt><strong><%= model_class.human_attribute_name(:publish_date) %>:</strong></dt>
<dd><%= #poster.publish_date %></dd>
<dt><strong>Author:</strong></dt>
<dd><%= link_to #poster.user.name, #poster.user %></dd>
<dt><strong>Type:</strong></dt>
<dd><%= #poster.type.name %></dd>
</dl>
<dt><strong>Image(s):</strong></dt>
<% #poster.poster_images.each do |p| %>
<%= content_tag "p_#{p.id}" do %>
<%= image_tag p.image.url(:medium) %>
<% end %>
<% end %>
<div class="form-actions">
<%= link_to t('.back', :default => t("helpers.links.back")),
posters_path, :class => 'btn' %>
<% if current_user && (current_user.has_role?(:admin) || current_user.id==#poster.user_id) %>
<% if can? :update, Poster %>
<%= link_to t('.edit', :default => t("helpers.links.edit")),
edit_poster_path(#poster), :class => 'btn' %>
<% end %>
<%= link_to t('.destroy', :default => t("helpers.links.destroy")),
poster_path(#poster),
:method => 'delete',
:data => { :confirm => t('.confirm', :default => t("helpers.links.confirm", :default => 'Are you sure?')) },
:class => 'btn btn-danger' %>
<% end %>
</div>
And now two my questions:
When I'm creating the poster, everything goes great. But when I'm trying to update my poster and push "edit", my form is coming in and I see all the fields that I had when I was creating poster. But if while CREATING poster I added a pic, when I see EDIT form, I have opened link for adding a pic. And if I use it, it's ok, but when I just edit my Name,for example, and save it without adding new pic, my "show.html.erb" shows me my previous pic and a sign of "broken" image after it. If I had two images, while updating poster, rails is trying to make me to add two more images or adds two broken-image signs itself. Any ideas?(if you understood what you've read above)
The person who is checking my app says that I forgot to add some keys in my "poster_images_attributes: :image" in the controller in "poster_params". I found here, in SOF, that it should be enough, but he says that it's enough for creating poster, but not for edit and delete actions. Any ideas what else should I write in poster_params? Thanks
Rails with Paperclip ignore empty attachments
That's what gave me solution for both of my questions!
poster_images_attributes: [:image, :id]
I have a form that save a question and five answers in the database but I don't know how I can save the answers, this is my form:
<%= form_for([:admin, #question]) do |f| %>
...
<%= f.fields_for :answers do |builder| %>
<%= builder.label :answer, "Risposta", :class => "v-align" %>
<%= builder.text_field :answer, :rows => 2 %>
<%= builder.label :correct, "Corretta", :class => "v-align" %>
<%= builder.check_box :correct %>
<% end %>
...
<% end %>
My models:
class Question < ActiveRecord::Base
has_many :answers
accepts_nested_attributes_for :answers, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
attr_accessible :answers_attributes, :quiz_id, :question, :sort_order, :point_value, :number_correct, :explanation
end
class Answer < ActiveRecord::Base
belongs_to :question
attr_accessible :question_id, :answer, :correct, :sort_order
end
And my "Question" controller:
def new
#question = Question.new
5.times { #question.answers.build }
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #question }
end
end
def create
#question = Question.new(params[:question])
respond_to do |format|
if #question.save
format.html { redirect_to admin_question_path(#question), :notice => 'Test was successfully created.' }
format.json { render :json => #question, :status => :created, :location => #question }
else
format.html { render :action => "new" }
format.json { render :json => #question.errors, :status => :unprocessable_entity }
end
end
end
What I should do to save question and answer in the database?
Thanks!!
You only miss accepts_nested_attributes_for :answersin the Question model.
See doc.
EDIT:
You should add answers_attributes to your attr_accessible list
You should take a look at two RailsCasts:
http://railscasts.com/episodes/196-nested-model-form-part-1 and http://railscasts.com/episodes/197-nested-model-form-part-2
They might help you a lot!
The man behind those casts, Ryan Bates, created a great gem to handle nested forms!
I'm trying to add a fields_for attribute to a nested rails form. Any time I try to create a new object, it returns
Message(#58819400) expected, got
Array(#18903800) ...
app/controllers/discussions_controller.rb:53:in
`create'
If I try to access nested fields_for from forms based on non-nested resources (aka "form_for #parent" instead of "form_for [#parent, #child]" it works fine. Code below - any help with this really appreciated.
Controller:
# GET /discussions/new
# GET /discussions/new.xml
def new
#forum = Forum.find(params[:forum_id])
#discussion = Discussion.new
#discussion.messages.build
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #discussion }
end
end
def create
#forum = Forum.find_by_id(params[:forum_id])
#discussion = #forum.discussions.new(params[:discussion])
#discussion.user = current_user
respond_to do |format|
if #discussion.save
format.html { redirect_to([#forum, #discussion], :notice => 'Discussion was successfu#ly created.') }
format.xml { render :xml => [#forum, #discussion], :status => :created, :location => #discussion }
else
format.html { render :action => "new" }
format.xml { render :xml => #discussion.errors, :status => :unprocessable_entity }
end
end
end
Models:
class Forum < ActiveRecord::Base
belongs_to :user
has_many :discussions, :dependent => :destroy
validates :title, :presence => true
accepts_nested_attributes_for :discussions, :allow_destroy => true
end
class Discussion < ActiveRecord::Base
belongs_to :user
belongs_to :forum
has_many :messages, :dependent => :destroy
validates :title, :presence => true
end
class Message < ActiveRecord::Base
belongs_to :user
validates :user, :presence => true
validates :content, :presence => true
end
The view:
<%= form_for [#forum, #discussion] do |f| %>
<% if #discussion.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#discussion.errors.count, "error") %> prohibited this discussion from being saved:</h2>
<ul>
<% #discussion.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<%= f.fields_for :messages do |builder| %>
<%= builder.label :content, "Message" %>
<%= builder.text_area :content, :rows => 10 %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And finally, the routing:
resources :forums do
resources :discussions do
resources :messages
end
end
Any help with this really appreciated - I'm completely stumped.
Arghhh - really sorry folks...I just realised I'd forgot the accepts_nested_attributes_for in the discussions model, & consequently forums could access discussions, but discussions couldn't get down to messages.
Thanks anyhow.
I have two models, links and tags, associated through a third, link_tags. The following code is in my Link model.
Associations:
class Link < ActiveRecord::Base
has_many :tags, :through => :link_tags
has_many :link_tags
accepts_nested_attributes_for :tags, :allow_destroy => :false,
:reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
end
class Tag < ActiveRecord::Base
has_many :links, :through => :link_tags
has_many :link_tags
end
class LinkTag < ActiveRecord::Base
belongs_to :link
belongs_to :tag
end
links_controller Actions:
def new
#link = #current_user.links.build
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #link }
end
end
def create
#link = #current_user.links.build(params[:link])
respond_to do |format|
if #link.save
flash[:notice] = 'Link was successfully created.'
format.html { redirect_to links_path }
format.xml { render :xml => #link, :status => :created, :location => #link }
else
format.html { render :action => "new" }
format.xml { render :xml => #link.errors, :status => :unprocessable_entity }
end
end
end
View code from new.html.erb:
<% form_for [current_user, #link], :url => account_links_path do |f| %>
<%= render :partial => "form", :locals => { :f => f } %>
<% end %>
And the corresponding partial:
<%= f.error_messages %>
<p>
<%= f.label :uri %><br />
<%= f.text_field :uri %>
</p>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<h2>Tags</h2>
<% f.fields_for :tags_attributes do |tag_form| %>
<p>
<%= tag_form.label :name, 'Tag:' %>
<%= tag_form.text_field :name %>
</p>
<% unless tag_form.object.nil? || tag_form.object.new_record? %>
<p>
<%= tag_form.label :_delete, 'Remove:' %>
<%= tag_form.check_box :_delete %>
</p>
<% end %>
<% end %>
<p>
<%= f.submit 'Update' %>
</p>
The following line of code, in the create action in the Link controller throws an error:
#link = #current_user.links.build(params[:link])
The error: Tag(#-621698598) expected, got Array(#-609734898)
Are there additional steps needed in the has_many => :through case? These seem to be the only indicated changes for the basic has_many case.
Take a look at the line of your code
<% f.fields_for :tags_attributes do |tag_form| %>
You need to use just :tags instead of :tags_attributes.
This will solve your issue
Make sure that You have build links and tags in your controller like
def new
#link = #current_user.links.build
#link.tags.build
end
I found this here on stackoverflow:
Rails nested form with has_many :through, how to edit attributes of join model?
please tell me if it worked.
In order for this to work, you need to pass in the right params hash:
params = {
:link => {
:tags_attributes => [
{:tag_one_attr => ...}, {:tag_two_attr => ...}
],
:link_attr => ...
}
}
And your controller will look like:
def create
#link = Link.create(params[:link]) # this will automatically build the rest for your
end
Try this:
<% f.fields_for :tags_attributes do |tag_form| %>
In your controller in the new action (that loads the form partial), are you building a #tag through your link?
So you should see something along the lines of:
#link = Link.new
#tag = #link.tags.build
It might be best to post the contents of the new and create action of your links_controller.
try
<% f.fields_for :tags do |tag_form| %>
(ie lose the _attributes in :tag_attributes) That's how I've usually done nested forms
You need to build a tag in your controller or in the view
def new
#link = #current_user.links.build
#link.tags.build
end
#in your view you can just use the association name
<% f.fields_for :tags do |tag_form| %>