Ruby on Rails - ActiveAdmin Posts - ruby-on-rails

i followed a Youtube Video to implement ActiveAdmin Theme in my Rails App,- and everything worked like a charm (i thought).
https://www.youtube.com/watch?v=i2x995hm8r8
I followed every Step he took and i am a little confused right now because i can't create posts.
Whenever i try to create a New Post and type in the tile, body and select a image- it just won't do anything. It doesn't even give me a Error Message.
posts_controller.rb
class PostController < ApplicationController
def index
#post = Post.all.order('created_at DESC')
end
def create
#post = Post.new(params[:post].permit(:title, :body))
if #post.save
redirect_to #post
else
render 'new'
end
end
def show
#post = Post.find(params[:id])
#post = Post.order("created_at DESC").limit(4).offset(1)
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(:title, :body))
redirect_to #post
else
render 'edit'
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to posts_path
end
private
def post_params
params.require(:post).permit(:title, :body)
end
end
ActiveAdmin.register Post do
posts.rb
permit_params :title, :body, :image
show do |t|
attributes_table do
row :title
row :body
row :image do
post.image? ? image_tag(post.image.url, height: '100') : content_tag(:span, "No image yet")
end
end
end
form :html => {:multipart => true} do |f|
f.inputs do
f.input :title
f.input :body
f.input :image, hint: f.post.image? ? image_tag(post.image.url, height: '100') : content_tag(:span, "Upload JPG/PNG/GIF image")
end
f.actions
end
end
post.rb
class Post < ApplicationRecord
belongs_to :user
validates :title, presence: true, length: {minimum: 5}
validates :body, presence: true, length: { maximum: 140}
has_attached_file :image, styles: { medium: "300x300>", thumb: "100x100>" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
end
EDIT I:
Started POST "/admin/posts" for 127.0.0.1 at 2018-03-20 14:30:24 +0100
Processing by Admin::PostsController#create as HTML
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"f+hfBD3lzgXEfz1q38/i3YciHsbb5LYWbbHUUsyIeOCaNSUReUUVVTBE//Dw0zXxSuFCzcMfYuUGDtIJlNb58w==", "post"=>{"title"=>"asdasdasd", "body"=>"asdasdasd"}, "commit"=>"Create Post"}
AdminUser Load (0.3ms) SELECT "admin_users".* FROM "admin_users" WHERE "admin_users"."id" = $1 ORDER BY "admin_users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
(0.2ms) BEGIN
(0.1ms) ROLLBACK
Rendering /Users/useruser/.rvm/gems/ruby-2.4.2/bundler/gems/activeadmin-2cf85fb03ab3/app/views/active_admin/resource/new.html.arb
Rendered /Users/useruser/.rvm/gems/ruby-2.4.2/bundler/gems/activeadmin-2cf85fb03ab3/app/views/active_admin/resource/new.html.arb (134.6ms)
Completed 200 OK in 230ms (Views: 148.3ms | ActiveRecord: 5.7ms)
If you need more of my Code just tell me what i should post in here.
I am just getting started with Ruby on Rails and Programming overall, so yes indeed, i am a Newb.
Thanks in advance!

From what I see in your edit 1, I see that you render new after submiting form. It means that your Post is not being saved. It also means that your application does exactly what it should do.
I assume that you are using latests Rails 5.
In Post model, you have belongs_to association (Post belongs to User).
In Rails 5, that means user or user_id has to be provided, to create Post (Post cannot belong to noone), else you won't be able to save.
Depending how you created association in table, you might be able to pass user or user_id in params.
Another way to create post belonging to particular user is:
#user = User.first
#post = #user.posts.build(post_params)
For ActiveAdmin, you can use default form that is created based on your model.
Just make sure you permit all params when creating it that way
ActiveAdmin.register Post do
permit_params %i[title body image user_id]
...
end
You can also set belongs_to :user association as optional.
Now some general advices from me:
First of all use proper indentation.
My advice to you is install Rubocop gem.
Second:
def show
#post = Post.find(params[:id])
#post = Post.order("created_at DESC").limit(4).offset(1)
end
That doesn't make much sense, you overwrite instance variable just after first assignment.
#post = Post.order("created_at DESC").limit(4).offset(1) is more of an index action, since it does not show particular posts, it show 2..5 newest posts.
def post_params
params.require(:post).permit(:title, :body)
end
Misses image attribute.
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(:title, :body))
redirect_to #post
else
render 'edit'
end
end
You duplicate params[:post].permit(:title, :body). You hgave already created private method for that. Use it here. Same goes for creation action, you duplicated it there too. Read what DRY code is about (google it).

You have belongs_to :user but never set a user_id. A belongs_to relation is by default required (in recent rails 4/5), and this will block the saving. The easiest way, for now, to fix this is to write it as following
belongs_to :user, optional: true
[EDIT: how to store current-user as owner of post]
If you want to automatically set the user to the currently logged in user, which I think is the intention, you can add the following to your active-admin configuration:
ActiveAdmin.register Post do
# .. keep your original configuration here ...
before_build do |record|
record.user = current_user
end
end
Or add an extra field to the form allowing the administrator to select the user?

Related

Using collection select in rails

I am trying to create a simple blog application. In which each post can be associated with the tags. This is my view
_form.hmtl.erb
<%= form.collection_select(:tag_ids, #tags, :id, :name, {}, :multiple => true) %>
This is my controller
posts_controller.rb
def new
#post = #topic.posts.new
#tag = #post.tags.new
#tags = Tag.all
end
def create
#post = #topic.posts.new(post_params)
if #post.save
redirect_to topic_posts_path
else
render 'new'
end
end
def post_params
params.require(:post).permit(:title,:content,:post_image, tag_ids: [])
end
end
Model Post.rb
has_and_belongs_to_many :tags
I am getting an error while creating new post "NoMethodError in Posts#create", "undefined method `map' for nil:NilClass". I am not able to find where the error is.
You should have a join table with name posts_tags.rb
class Post_Tag < ApplicationRecord
belongs_to :tag
belongs_to :post
end
so you have already some tags which you want to be selected with post and join table should be updated with post_id and tag_id
change this in your form_partial: -
<%= select_tag "tag_ids", options_for_select(#tags,:id,:name),{}, multiple: true%> <br/><br/>
Note: - you should not use form.collection_select(:tag_ids...) Reason being form_for is used here for #post object and tag_ids is not attribute of #post object.
so on submitting form you should get array of tag's ids in params[:tag_ids]
def create
#post = #topic.posts.new(post_params)
if #post.save
#create join table for tags that are associated with post
#post.tags << Tag.find(params[:tag_ids])
redirect_to topic_posts_path
else
render 'new'
end
end
so here you can get
#post.tags => which will return you collection of tags associated with the post
if you are using this scenario you have to make MANY TO MANY relation between these two models.
has_and_belongs_to_many :tags
then in form you should use like
form.collection_select(:post, :tag_id, Tag.all, :id, :name_with_initial, prompt: true)
The #tags variable is missing from your create action in controller - you have declared it in new, but not in create. It may cause error in view if save was unsucessful and action tries to re-render the form.
Not sure if that's all, because I'm not sure where the error is thrown exactly. But as you said in one of the comments - it works when you use Tag.all instead of #tags.

In Rails How to display errors in my comment form after I submit it?

I have a very straight-forward task to fulfil --- just to be able to write comments under posts and if the comments fail validation display error messages on the page.
My comment model uses a gem called Acts_as_commentable_with_threading, which creates a comment model after I installed.
On my post page, the logic goes like this:
Posts#show => display post and a form to enter comments => after the comment is entered, redisplay the Post#show page which has the new comment if it passes validation, otherwise display the error messages above the form.
However with my current code I can't display error messages if the comment validation fails. I think it is because when I redisplay the page it builds a new comment so the old one was erased. But I don't know how to make it work.
My codes are like this:
Comment.rb:
class Comment < ActiveRecord::Base
include Humanizer
require_human_on :create
acts_as_nested_set :scope => [:commentable_id, :commentable_type]
validates :body, :presence => true
validates :first_name, :presence => true
validates :last_name, :presence => true
# NOTE: install the acts_as_votable plugin if you
# want user to vote on the quality of comments.
#acts_as_votable
belongs_to :commentable, :polymorphic => true
# NOTE: Comments belong to a user
belongs_to :user
# Helper class method that allows you to build a comment
# by passing a commentable object, a user (could be nil), and comment text
# example in readme
def self.build_from(obj, user_id, comment, first_name, last_name)
new \
:commentable => obj,
:body => comment,
:user_id => user_id,
:first_name => first_name,
:last_name => last_name
end
end
PostController.rb:
class PostsController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
def show
#post = Post.friendly.find(params[:id])
#new_comment = Comment.build_from(#post, nil, "", "", "")
end
end
CommentsController:
class CommentsController < ApplicationController
def create
#comment = build_comment(comment_params)
respond_to do |format|
if #comment.save
make_child_comment
format.html
format.json { redirect_to(:back, :notice => 'Comment was successfully added.')}
else
format.html
format.json { redirect_to(:back, :flash => {:error => #comment.errors}) }
end
end
end
private
def comment_params
params.require(:comment).permit(:user, :first_name, :last_name, :body, :commentable_id, :commentable_type, :comment_id,
:humanizer_answer, :humanizer_question_id)
end
def commentable_type
comment_params[:commentable_type]
end
def commentable_id
comment_params[:commentable_id]
end
def comment_id
comment_params[:comment_id]
end
def body
comment_params[:body]
end
def make_child_comment
return "" if comment_id.blank?
parent_comment = Comment.find comment_id
#comment.move_to_child_of(parent_comment)
end
def build_comment(comment_params)
if current_user.nil?
user_id = nil
first_name = comment_params[:first_name]
last_name = comment_params[:last_name]
else
user_id = current_user.id
first_name = current_user.first_name
last_name = current_user.last_name
end
commentable = commentable_type.constantize.find(commentable_id)
Comment.build_from(commentable, user_id, comment_params[:body],
first_name, last_name)
end
end
comments/form: (this is on the Posts#show page)
<%= form_for #new_comment do |f| %>
<% if #new_comment.errors.any? %>
<div id="errors">
<h2><%= pluralize(#new_comment.errors.count, "error") %> encountered, please check your input.</h2>
<ul>
<% #new_comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<% end %>
I would instead use nested routes to create a more restful and less tangled setup:
concerns :commentable do
resources :comments, only: [:create]
end
resources :posts, concerns: :commentable
This will give you a route POST /posts/1/comments to create a comment.
In your controller the first thing you want to do is figure out what the parent of the comment is:
class CommentsController < ApplicationController
before_action :set_commentable
private
def set_commentable
if params[:post_id]
#commentable = Post.find(params[:post_id])
end
end
end
This means that we no longer need to pass the commentable as form parameters. Its also eliminates this unsafe construct:
commentable = commentable_type.constantize.find(commentable_id)
Where a malicous user could potentially pass any class name as commentable_type and you would let them find it in the DB... Never trust user input to the point where you use it to execute any kind of code!
With that we can start building our create action:
class CommentsController < ApplicationController
before_action :set_commentable
def create
#comment = #commentable.comments.new(comment_params) do |comment|
if current_user
comment.user = current_user
comment.first_name = current_user.first_name
comment.last_name = current_user.last_name
end
end
if #comment.save
respond_to do |format|
format.json { head :created, location: #comment }
format.html { redirect_to #commentable, success: 'Comment created' }
end
else
respond_to do |format|
format.html { render :new }
format.json { render json: #comment.errors, status: 422 }
end
end
end
private
# ...
def comment_params
params.require(:comment).permit(:first_name, :last_name, :body, :humanizer_answer, :humanizer_question_id)
end
end
In Rails when the user submits a form you do not redirect the user back to the form - instead you re-render the form and send it as a response.
While you could have your CommentsController render the show view of whatever the commentable is it will be quite brittle and may not even provide a good user experience since the user will see the top of the post they where commenting. Instead we would render app/views/comments/new.html.erb which should just contain the form.
Also pay attention to how we are responding. You should generally avoid using redirect_to :back since it relies on the client sending the HTTP_REFERRER header with the request. Many clients do not send this!
Instead use redirect_to #commentable or whatever resource you are creating.
In your original code you have totally mixed up JSON and HTML responses.
When responding with JSON you do not redirect or send flash messages.
If a JSON POST request is successful you would either:
Respond with HTTP 201 - CREATED and a location header which contains the url to the newly created resource. This is preferred when using SPA's like Ember or Angular.
Respond with HTTP 200 - OK and the resource as JSON in the response body. This is often done in legacy API's.
If it fails do to validations you should respond with 422 - Unprocessable Entity - usually the errors are rendered as JSON in the response body as well.
Added.
You can scrap your Comment.build_from method as well which does you no good at all and is very idiosyncratic Ruby.
class PostsController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
def show
#post = Post.friendly.find(params[:id])
#new_comment = #post.comments.new
end
end
Don't use line contiuation (\) syntax like that - use parens.
Don't:
new \
:commentable => obj,
:body => comment,
:user_id => user_id,
:first_name => first_name,
:last_name => last_name
Do:
new(
foo: a,
bar: b
)
Added 2
When using form_for with nested resources you pass it like this:
<%= form_for([commentable, comment]) do |f| %>
<% end %>
This will create the correct url for the action attribute and bind the form to the comment object. This uses locals to make it resuable so you would render the partial like so:
I'm assuming your form_for submits a POST request which triggers the HTML format in CommentsController#create:
def create
#comment = build_comment(comment_params)
respond_to do |format|
if #comment.save
make_child_comment
format.html
format.json { redirect_to(:back, :notice => 'Comment was successfully added.')}
else
format.html
format.json { redirect_to(:back, :flash => {:error => #comment.errors}) }
end
end
end
So, if #comment.save fails, and this is an HTML request, the #create method renders create.html. I think you want to render Posts#show instead.
Keep in mind that if validations fail on an object (Either by calling save/create, or validate/valid?), the #comment object will be populated with errors. In other words calling #comment.errors returns the relevant errors if validation fails. This is how your form is able to display the errors in #new_comment.errors.
For consistency, you'll need to rename #new_comment as #comment in the posts#show action, otherwise you'll get a NoMethodError on Nil::NilClass.
TL;DR: You're not rendering your form again with your failed #comment object if creation of that comment fails. Rename to #comment in posts, and render controller: :posts, action: :show if #comment.save fails from CommentsController#create
I have figured out the answer myself with the help of others here.
The reason is that I messed up with the JSON format and html format (typical noobie error)
To be able to display the errors using the code I need to change two places ( and change #comment to #new_comment as per #Anthony's advice).
1.
routes.rb:
resources :comments, defaults: { format: 'html' } # I set it as 'json' before
2.
CommentsController.rb:
def create
#new_comment = build_comment(comment_params)
respond_to do |format|
if #new_comment.save
make_child_comment
format.html { redirect_to(:back, :notice => 'Comment was successfully added.') }
else
commentable = commentable_type.constantize.find(commentable_id)
format.html { render template: 'posts/show', locals: {:#post => commentable} }
format.json { render json: #new_comment.errors }
end
end
end

undefined method `image' in my view

I am using Paperclip, and my only problem is that in my image tag, I have an undefined method "image".
<%= image_tag #posts.image.url(:medium) %>
is where my error is occurring. When I loaded a new migration, I accidentally did "rails g paperclip user image" instead of "rails g paperclip posts image" so I went into my code and changed "user" to "posts." I asked something similar and someone mentioned that it was with my schema.rb file(?).
Just to be safe, this is my post controller:
class PostsController < ApplicationController
def index
#posts = Post.all.order('created_at DESC')
end
def new
#post = Post.new
if #post.save
redirect_to #post
else
render 'new'
end
end
def create
#post = Post.new(post_params)
#post.save
redirect_to #post
end
def show
#post = Post.find(params[:id])
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(:title, :body))
redirect_to #post
else
render 'edit'
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to root_path
end
private
def post_params
params.require(:post).permit(:title, :body, :image)
end
end
but here is my migration file:
class AddAttachmentImageToUsers < ActiveRecord::Migration
def self.up
change_table :posts do |t|
t.attachment :image
end
end
def self.down
remove_attachment :posts, :image
end
end
and my user.rb file:
has_attached_file :image, :styles => { large: '600x600>', medium: '300x300>', thumb: '150x150#' }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
From the comments and your code, it looks like your #posts variable is either empty or undefined. To add to the original answer, here's what I'd do:
#app/controllers/posts_controller.rb
class PostsController < ActionController::Base
def index
#posts = Post.all.order(created_at: :desc)
end
end
#app/views/posts/index.html.erb
<% if #posts.any? %>
<% #posts.each do |post| %>
<%= image_tag post.image.url(:medium) %>
<% end %>
<% end %>
You must have the #posts variable referenced in the view which corresponds to the action you're running. From seeing your comments, it appears this might not be the case.
You need to be referencing single instances of the Post model, in order to have the image method available.
If it is not available, it either means you don't have the #posts variable declared properly, or your Paperclip gem is not set up properly.
this is my user.rb file
haha okay. THIS is the problem.
Make sure you put this in your post.rb file:
#app/models/post.rb
class Post < ActiveRecord::Base
has_attached_file :image, :styles => { large: '600x600>', medium: '300x300>', thumb: '150x150#' }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
end
Paperclip basically links stored images to database records. Thus, in order to append the image method to your model, you have to have the Paperclip options appended to it.
Putting the paperclip calls in user.rb will add the image method to your User model. You need to put those lines in the Post model.
BTW I met the guys who made Paperclip:
that it was with my schema.rb file(?).
The schema.rb file is located in /config/db/schema.rb.
Essentially, each time you migrate to your DB, the schema is updated, so that in the event you need to repopulate the db, Rails will be able to pull a pre-built set of SQL calls to do it.
Indeed, it is recommended that you use rake db:schema:load to
rebuild a database (rather than rake db:migrate). HOWEVER (VERY
IMPORTANT), IT DELETES ANY DATA in that database, making it
unadvisable to use it for anything other than building new db's.
You can read about Schema.rb here.
In regards to what your friend was saying, if you go into your schema.rb file, you'll be able to see which table has the paperclip columns added to it. By generating the migration for the users table, you may have caused a conflict.
You need to access image for one post at a time so you need to traverse the posts collection and fetch image for each post like this
<% #posts.each do |post| %>
<%= image_tag post.image.url(:medium) %>
<% end %>
I think the problem might be how you changing "user" to "posts.".it would be okay to just change controller or view name,but change model is a different thing that you have to generate a migration to change table name

friendly_id creates new entry on UPDATE

I'm using friendly_id 5.1.0, and when I try to update an entry, for exemple creating a new Article, instead of updating the data of the entry, it creates a new one.
I have slugged the title and when I don't change it when editing an article, it creates a slug with a bunch of numbers/letters :
http://localhost:3000/articles/first-article-2d392b8e-92b8-44b0-ad67-50dd674f7aaa
Here's my article.rb Model :
class Article < ActiveRecord::Base
extend FriendlyId
has_many :comments
friendly_id :title, :use => :slugged
validates :title, presence: true,
length: { minimum: 5}
def should_generate_new_friendly_id?
new_record? || title_changed?
end
when I add :use => [:slugged, :history], when I update an entry and keep the same title, it can't save it because my :slug field is unique :true.
Here's my articles_controller.rb :
class ArticlesController < ApplicationController
def index
#articles = Article.all.order(created_at: :desc)
end
def show
#article = Article.friendly.find(params[:id])
if request.path != article_path(#article)
redirect_to #article, status: :moved_permanently
end
end
def new
#article = Article.new
end
def edit
#article = Article.friendly.find(params[:id])
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def update
#article = Article.friendly.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
def destroy
#article = Article.friendly.find(params[:id])
#article.destroy
redirect_to articles_path
end
private
def article_params
params.require(:article).permit(:title, :text)
end
end
Here's my GitHub repository whith my (unfinished) project : https://github.com/TheDoctor314/blog
This issue has nothing to do with FriendlyID.
Your problem is here (a form used on both new and edit):
<%= bootstrap_form_for :article, url: articles_path do |f| %>
It does not attempt to use your #article object to built that form. So your form always issues a POST request to articles_path, which results in create every time. What you should do instead is:
<%= bootstrap_form_for #article do |f| %>
That way form builder will check if that object is persisted? already, and if so, generate a form that issues a PATCH request to that specific article that triggers an update action. It will try to guess the URL by itself. And it will succeeed only if you follow conventions tightly enough.
If #article is not persisted?, it will do what it did: make a POST to articles_path.
Permit id in params
params.require(:article).permit(:id, :title, :text)
Hope that helps!
The Edit form is routing to create action for articles controller instead of update action. You need to change your form path, when editing the files.
If you see the articles index action, you can see new articles are being added, instead of updating

One to Many Association Object Will Not Save

I set up a has_many belongs_to relationship in my two models and followed Ryan Bates' screencast on how to set up the controller. When I submit my form to create the new object, the nested object does not save for some reason. Here are my models:
class Auction < ActiveRecord::Base
has_many :bids, dependent: :destroy
end
class Bid < ActiveRecord::Base
belongs_to :auction
belongs_to :user
default_scope -> { order(created_at: :desc) }
validates :user_id, presence: true
validates :auction_id, presence: true
end
and my nested object controller:
class BidsController < ApplicationController
def index
#auction = Auction.find(params[:auction_id])
#bids = #auction.bids
end
def new
#auction = Auction.find(params[:auction_id])
#bid = #auction.bids.build
end
def create
#auction = Auction.find(params[:auction_id])
#bid = #auction.bids.create(params[:bid])
#bid.save
if #bid.save
flash[:success] = "Bid has been successfully placed."
else
#bid.errors
render 'new'
end
end
def destroy
#auction = Auction.find(params[:auction_id])
#bid = #auction.bids.find
#bid.destroy
flash[:notice] = "Successfully destroyed Bid."
redirect_to auction_url(#bid.article_id)
end
end
my form:
<h1>Create a New Bid</h1>
<%= form_for ([#auction, #bid]) do |f|%>
<p>
<%= f.submit %>
</p>
<%end%>
and my terminal output:
Started POST "/auctions/1/bids" for 127.0.0.1 at 2014-11-30 17:59:13 -0600
Processing by BidsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"dkZBcab1rgZjtJGF3LAJ//exK6liglZ0Fy4mg7HWEt0=", "commit"=>"Create Bid", "auction_id"=>"1"}
Auction Load (0.1ms) SELECT "auctions".* FROM "auctions" WHERE "auctions"."id" = ? LIMIT 1 [["id", 1]]
(0.0ms) begin transaction
(0.0ms) commit transaction
(0.0ms) begin transaction
(0.0ms) rollback transaction
(0.0ms) begin transaction
(0.0ms) rollback transaction
Thanks for your help.
Your bid object needs a user_id because you have validates :user_id, presence: true in the class definition.
When you call #bid.save in the controller, however, #bid does not have a user_id value, therefore the transaction gets rolled back because of the failing validation.
You should be able to see this by looking at #bid.errors.full_messages in the create action, after you've called #bid.save. (Look up the pry gem if you're not already familiar with it...it would be a perfect tool to let you do this inspection.)
Try replacing your create action with this:
def create
#auction = Auction.find(params[:auction_id])
#bid = #auction.bids.new params[:bid].merge(user_id: current_user.id)
if #bid.save
flash[:success] = "Bid has been successfully placed."
else
flash[:error] = #bid.errors.full_messages.join('. ')
render 'new'
end
end
This assumes that you have access to the current user in the controller as current_user. Devise and other popular auth solutions supply this, or you can do so yourself.
Note also that your original code tries to write #bid to the database 3 separate times, which is twice more than you need to. Here are the offending lines:
def create
...
#bid = #auction.bids.create(params[:bid])
#bid.save
if #bid.save
...
#create instantiates an object and attempts to write it to the database. In my code above, I've replaced #auction.bids.create(params...) with #auction.bids.new(params...). This initializes #bid without trying to persist it to the db.
I also removed the first #bid.save because the line below it if #bid.save will accomplish the same thing.
Finally, your line #bid.errors doesn't do anything useful. I modified it to store the error messages in your flash hash, which you can then use in your view to display the errors to the user.

Resources