Rails 6 model wont save in controller - ruby-on-rails

I been working on a sort of gun display social media website thing but I ran into a problem where after I added the user_id to the gun model the save view will go to the create controller but wont save when the if save line (in the controller) is suppose to run. It worked in rails console but not by the controller.
schema
ActiveRecord::Schema.define(version: 2021_02_06_222048) do
create_table "guns", force: :cascade do |t|
t.integer "year"
t.string "model"
t.string "condition"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "user_id", null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
model
class Gun < ApplicationRecord belongs_to :users
view
<h1>Create your Gun here</h1>
<form method = "post" action = <%=gun_index_url%>>
<label for = "gun_model">Gun model</label>
<input
type = "text"
name = "gun[model]"
id = "gun_model">
<label for = "gun_condtion">Condtion</label>
<input
type = "text"
name = "gun[condition]"
id = "gun_condtion">
<label for = year>Year manerfacterd</label>
<input
type = "number"
value = "2000"
name = "gun[year]"
id = "gun_year">
<input
type = "hidden"
value = "<%=current_user.id%>"
name = "gun[user_id]"
id = "user_id">
<input
type = "hidden"
value = "<%=form_authenticity_token%>"
name = "authenticity_token">
<input type="submit" value="sumbit">
</form>
Controller model
class GunController < ApplicationController
before_action :authenticate_user!, only: [:new]
def index
#guns = Gun.all
render :index
end
def new
#gun = Gun.new
render :new
end
def edit
#gun = Gun.find(params[:id])
render :edit
end
def create
#gun = Gun.new(gun_params)
if #gun.save
redirect_to gun_url(#gun)
else
redirect_to new_gun_url
raise ArgumentError.new
end
end
def show
#gun = Gun.find(params[:id])
render :show
end
def update
#gun = Gun.find(params[:id])
if #gun.update(gun_params)
redirect_to gun_url(#gun)
else
render :edit
raise ArgumentError.new
end
end
def destroy
#gun = Gun.find(params[:id])
#gun.destroy
redirect_to gun_index_url
end
private
def gun_params
params.require(:gun).permit(:condition ,:year ,:model, :user_id)
end

I found out that the
belongs_to :users
was not supost to be pular and should have been
belongs_to :user

typically when a model wont save its a validation error. use the bang (!) methods to figure out what actually cases it..
so, instead of save use save! or instead of update, update!

Related

Create action in controller to create an appointment between users and doctors - 204 NO RESPONSE

I'm building an API for an app where a user can make appointments with a doctor.
Everything is working just fine but it's returning 204 - No content when I try to post a new appointment in Postman.
My schema:
create_table "appointments", force: :cascade do |t|
t.date "date"
t.time "time"
t.bigint "user_id"
t.bigint "doctor_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["doctor_id"], name: "index_appointments_on_doctor_id"
t.index ["user_id"], name: "index_appointments_on_user_id"
end
create_table "doctors", force: :cascade do |t|
t.string "name"
t.string "speciality"
t.integer "years_of_experience"
t.integer "likes"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email"
t.string "password_digest"
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_foreign_key "appointments", "doctors"
add_foreign_key "appointments", "users"
end
My appointments controller:
class Api::V1::AppointmentsController < ApplicationController
include CurrentUserConcern
def index
#appointments = Appointment.all
render json: #appointments
end
def create
if #current_user
#appointment = #current_user.appointments.build(appointment_params)
if #appointment.save
render json: #appointment
else
render json: { status: 401 }
end
end
end
private
def appointment_params
params.require(:appointment).permit(:time, :date, #current_user.id, :doctor_id)
end
end
First of all there's not need of sending #current_user.id in appointment_params as user_id will be assigned automatically when this line #appointment = #current_user.appointments.build(appointment_params) execute.
Coming to your issue make sure you are sending a POST request and "body" data in the correct JSON format from PostMan. As per your method appointment_params the request body should look like this
{
appointment: {
time: "",
date: "",
doctor_id:
}
}

Rails: Show action in controller is unable to access foreign key value

I am attempting to build a chess application, and am testing the logic of the ability to only select pieces that match the color of the player. The method in the Piece model is passing all RSpec tests, but I run into an error while testing the show action in the pieces controller. I have narrowed down the issue to the pieces controller being unable to access the white_player_id column. It is able to access all other columns in the games table. I do not have white_player or black_player models, but I do assign the IDs based on the current_user. When a game is created, the current_user automatically becomes the white player (user.id = white_player_id), and the black player is the second user who joins the game after its creation.
How can I get the pieces controller to access the white_player_id value? I don't want to create white_player and black_player models, because they are only needed for color checks.
If it matters, the database I am using is PostgreSQL.
This is the Piece model:
class Piece < ApplicationRecord
belongs_to :game
validates :x, numericality: true
validates :y, numericality: true
scope :black_pieces, ->() { where(color: 'black') }
scope :white_pieces, ->() { where(color: 'white') }
scope :active, -> { where(captured: false) }
def white?
color == 'white'
end
def black?
color == 'black'
end
def piece_color_matches_user_color?(user)
if color == 'white' && user.id == game.white_player_id
true
elsif color == 'black' && user.id == game.black_player_id
true
else
false
end
end
# ...
end
This is the Game model:
class Game < ApplicationRecord
has_many :pieces
belongs_to :user
before_save :start_game_when_black_player_is_added
after_create :populate
scope :available, -> { where(state: "pending") }
after_create :current_user_is_white_player
def add_black_player!(player)
self.black_player_id = player.id
self.total_players = 2
save
end
def current_user_is_white_player
self.white_player_id = user_id
end
def populate
(1..8).each do |piece|
pieces.create(x: piece, y: 2, color: 'white', type: 'Pawn')
pieces.create(x: piece, y: 7, color: 'black', type: 'Pawn')
end
["Rook", "Knight", "Bishop", "King", "Queen", "Bishop", "Knight", "Rook"].each.with_index(1) do |klass, index|
pieces.create(x: index, y: 1, color: 'white', type: klass)
pieces.create(x: index, y: 8, color: 'black', type: klass)
end
end
end
This is the User model:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :games
end
This is the Pieces controller:
class PiecesController < ApplicationController
before_action :authenticate_user!
skip_before_action :verify_authenticity_token
def show
#piece = Piece.find_by_id(params[:id])
if #piece.blank?
return render_not_found
end
if #piece.game.white_player_id # white_player_id does not exist to the controller
# returns 404 error
# if #piece.piece_color_matches_user_color?(current_user)
return render plain: "Success"
else
render_not_found
end
# #game = #piece.game
# #pieces = #game.pieces.all
end
def update
#piece = Piece.find_by_id(params[:id])
#game = #piece.game
x_target = piece_params[:x].to_i
y_target = piece_params[:y].to_i
if #piece.attempt_move(x_target, y_target)
#piece.save
else
return render_not_found
end
render plain: "Success"
end
private
def render_not_found(status=:not_found)
render plain: "#{status.to_s.titleize} :(", status: status
end
def piece_params
params.require(:piece).permit(:x, :y)
end
end
This is the schema:
ActiveRecord::Schema.define(version: 20180109032015) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "games", force: :cascade do |t|
t.string "name"
t.boolean "finished"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "total_players"
t.bigint "white_player_id"
t.bigint "black_player_id"
t.string "state", default: "pending", null: false
t.bigint "user_id"
t.bigint "winner_id"
end
create_table "pieces", force: :cascade do |t|
t.bigint "game_id"
t.string "type"
t.integer "x"
t.integer "y"
t.string "color"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "captured", default: false
t.index ["game_id"], name: "index_pieces_on_game_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end
This is the error:
PiecesController pieces#show action should return success if the piece color matches the user color
Failure/Error: expect(response).to have_http_status :success
expected the response to have a success status code (2xx) but it was 404
# ./spec/controllers/pieces_controller_spec.rb:48:in `block (3 levels) in <top (required)>'
This is the Controller spec:
RSpec.describe PiecesController, type: :controller do
describe 'pieces#show action' do
it 'should return success if the piece color matches the user color' do
game = FactoryBot.create(:game)
piece = game.pieces.active.find_by({x: 1, y: 2})
sign_in game.user
get :show, params: { id: piece.id }
expect(response).to have_http_status :success
end
end
end
This is the Model spec:
RSpec.describe Piece, type: :model do
describe '#piece_color_matches_user_color?' do
it '#piece_color_matches_user_color? returns true if the piece color and user color match' do
game = FactoryBot.create(:game)
piece = game.pieces.active.find_by({x: 1, y: 2})
user = game.user
result = piece.piece_color_matches_user_color?(user)
expect(result).to eq true
end
end
end
Great and well-described question!
With ActiveRecord, after it queries your database it maps each returned column to a public method inside itself; so there's nothing stopping you from accessing the column directly your controller — or any class.
Having said, you have an after_create callback in your game.rb which is assigning a User#id to your Game#white_player_id, but it's not saving that column. Changing it to before_create :current_user_is_white_player should get you on the right track.

Rails do not save form to the db

I am trying to make a association between Printlist and Product, Template and Paper Type, but I'm getting an error. When I submit the new form, it redirects to the index route, but ramains at the same new page and do not save the info to the DB.
Controller:
class PrintlistsController < ApplicationController
before_action :set_printlist, only: [:show, :edit, :update, :destroy]
def index
#printlists = Printlist.all
#preco = calcular_preco(Printlist.count(:id),Printlist.count(:id),Printlist.count(:id),Printlist.count(:id),Printlist.count(:id),Printlist.count(:id),Printlist.count(:id))
end
def show
end
def new
#printlist = Printlist.new
end
def edit
end
def create
#binding.pry
#product = Product.where('codref': product_params['codref'])
#template = Poster.find(layout_params['id'])
#size = Cartaze.find(cartaz_params['id'])
#if product.nil?
# product = Product.new
# product.codref = product_params['codref']
# product.title = product_params['title']
# product.tipo = product_params['tipo']
# product.size = product_params['size']
# product.save
#end
#printlist = Printlist.new(printlist_params)
##printlist.product = product
##printlist.template = template
##printlist.size = size
respond_to do |format|
if #printlist.save
format.html { redirect_to printlists_path , notice: 'Impression was successfully created.' }
format.json { render :show, status: :created, location: #printlist }
else
format.html{ render :new }
format.json{ render json: #printlistst.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #printlist.update(printlist_params)
format.html { render action: "edit" }
format.json { render :show, status: :ok, location: #printlist }
else
format.html { render :edit }
format.json { render json: #printlist.errors, status: :unprocessable_entity }
end
end
end
def destroy
#printlist = Printlist.find(params[:id])
#printlist.destroy
respond_to do |format|
format.html { redirect_to(Printlists_path) }
format.xml { head :ok }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_printlist
#printlist = Printlist.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def printlist_params
params.require(:printlist).permit(:product_id, :poster_id, :cartaze_id)
end
def calcular_preco(na0, na1, na2, na3, na4, na5, na6)
#formulando preco
#precos = {a0: 1, a1: 2, a2: 3, a3: 4, a4: 5, a5: 6, a6: 7}
#cartaz = Cartaze.all
pr = HashWithIndifferentAccess.new(#cartaz.map{ |c| [c.size.to_s,c.price.to_f] }.to_h)
#precos = HashWithIndifferentAccess.new({a0: 1, a1: 2, a2: 3, a3: 4, a4: 5, a5: 6, a6: 7})
#preco_total = (na0 * pr[:A0]) + (na1 * pr[:A1]) + (na2 * pr[:A2]) + (na3 * pr[:A3]) + (na4 * pr[:A4]) + (na5 * pr[:A5]) + (na6 * pr[:A6])
end
#def product_params
#params.require(:product_id).permit(:product_id)
#end
#def poster_params
# params.require(:poster).permit(:id)
#end
#def cartaze_params
# params.require(:cartaze).permit(:id, :size)
#end
end
new.html.erb.rb form:
<%= render "/partials/sidebar" %>
<div class="conteudo-dash">
<div class="linha-dash">
<div class="panel panel-defaul col-md-6">
<div class="panel-body">
<h2>Cadastro de Cartaz</h2>
<%= form_for(#printlist, url: printlists_path) do |f|%>
<%= f.collection_select(:product_id, Product.all, :id, :title,{}, {class: "form-control col-md-3"}) %>
<%= f.collection_select(:poster_id, Poster.all, :id, :name,{},{class: "form-control"}) %>
<%= f.collection_select(:cartaze_id, Cartaze.all, :id, :size, {},{class: "form-control"}) %><br>
<%= f.submit "Salvar Produto", class: "btn btn-success" %>
<% end %>
</div>
</div>
</div>
</div>
</div>
printlist.rb model:
class Printlist < ApplicationRecord
include ActiveModel::ForbiddenAttributesProtection
belongs_to :posters
belongs_to :cartazes
belongs_to :products
end
schema.rb:
ActiveRecord::Schema.define(version: 20170523202905) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "cartazes", force: :cascade do |t|
t.string "product"
t.decimal "price", precision: 7, scale: 2
t.string "tipo"
t.string "size"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "dashboards", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "products_id"
t.integer "posters_id"
t.integer "cartazes_id"
t.index ["cartazes_id"], name: "index_dashboards_on_cartazes_id", using: :btree
t.index ["posters_id"], name: "index_dashboards_on_posters_id", using: :btree
t.index ["products_id"], name: "index_dashboards_on_products_id", using: :btree
end
create_table "dashboards_posters", id: false, force: :cascade do |t|
t.integer "dashboard_id", null: false
t.integer "poster_id", null: false
t.index ["dashboard_id", "poster_id"], name: "index_dashboards_posters_on_dashboard_id_and_poster_id", using: :btree
end
create_table "posters", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "printlists", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "product_id"
t.integer "poster_id"
t.integer "cartaze_id"
t.index ["cartaze_id"], name: "index_printlists_on_cartaze_id", using: :btree
t.index ["poster_id"], name: "index_printlists_on_poster_id", using: :btree
t.index ["product_id"], name: "index_printlists_on_product_id", using: :btree
end
create_table "products", force: :cascade do |t|
t.string "title"
t.decimal "price"
t.string "tipo"
t.string "size"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.decimal "preco_promo", precision: 7, scale: 2
t.string "codref"
end
create_table "servicos", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
end
add_foreign_key "dashboards", "cartazes", column: "cartazes_id"
add_foreign_key "dashboards", "posters", column: "posters_id"
add_foreign_key "dashboards", "products", column: "products_id"
end
EDIT
routes.rb
Rails.application.routes.draw do
get 'notification/create'
resources :products
devise_for :users
root 'home#index'
# user_root_path 'dashboard#index' # DEPOIS DO CLIENTE ESTAR LOGADO redireciona pra dashboard
post 'pgtcheckout/create'
post 'notification', to: 'notification#create'
resources :users
get 'pgtcheckout' => 'pgtcheckout#index'
get 'pgtcheckout/new' => 'pgtcheckout#new'
resources :dashboards
resources :product
resources :posters
resources :printlists
Console Output
Started POST "/printlists" for ::1 at 2017-05-29 13:53:04 -0300
Processing by PrintlistsController#create as HTML
Parameters: {"utf8"=>"V", "authenticity_token"=>"KrKq5k71/exf2nnw56F43IbbZz7CRdjnsvTSulSNAM9Uj8lPB8tnQ9BfDifeXlMLVTNqIs6/T1dSeIS5zeph
sQ==", "printlist"=>{"product_id"=>"7", "poster_id"=>"4", "cartaze_id"=>"3"}, "commit"=>"Salvar Produto"}
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1
]]
(0.0ms) BEGIN
(0.0ms) ROLLBACK
Rendering printlists/new.html.erb within layouts/application
Rendered partials/_sidebar.html.erb (12.0ms)
Product Load (1.0ms) SELECT "products".* FROM "products"
Poster Load (0.0ms) SELECT "posters".* FROM "posters"
Cartaze Load (0.0ms) SELECT "cartazes".* FROM "cartazes"
Rendered printlists/new.html.erb within layouts/application (52.0ms)
Completed 200 OK in 1117ms (Views: 1106.2ms | ActiveRecord: 2.0ms)
Debug Output:
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
utf8: "✓"
authenticity_token: KrKq5k71/exf2nnw56F43IbbZz7CRdjnsvTSulSNAM9Uj8lPB8tnQ9BfDifeXlMLVTNqIs6/T1dSeIS5zephsQ==
printlist: !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
product_id: '1'
poster_id: '3'
cartaze_id: '3'
permitted: false
commit: Salvar Produto
The new Printlist object is failing a validation when executing #printlist.save on create action; that's why you get a (0.0ms) ROLLBACK in your logs.
So, #printlist.save returns false and executes format.html { render :new }; as instructed in create action:
if #printlist.save
format.html { redirect_to printlists_path , notice: 'Impression was successfully created.' }
format.json { render :show, status: :created, location: #printlist }
else
format.html{ render :new }
format.json{ render json: #printlistst.errors, status: :unprocessable_entity }
end
To spot the error, use save! instad of save (this is only temporary), that will raise an exception describing why the object is not valid, and thus not saving.
With save! in place, now you will get an exception (instead of a ROLLBACK) in your logs with the error message.
Once you spot why your validation fails, you can fix it; and don't forget to change back save! to save.

Duplicating record and it's children - but children get deleted from old record

My problem is similar to:
My cloning method is stealing the children from the original model
But I can't seem to get the solution for this to work with mine. I'm trying to create an order exchange form which involves populating the form with the old record details. So when I save the form it creates a new Order record but the children seem to get deleted from the old Order record and siphoned into the new one.
Here's the code:
def new
#old_order = Order.includes(:line_items).find(params[:id])
#order = Order.new #old_order.attributes
#order.line_items = []
#old_order.line_items.each do |old|
new = old.dup # the line_item id is set before creation.
new.order_id = #order.id
new.save!
#order.line_items << new
#old_order.line_items << old # this was to see if the old line_items would reappend to the old order. Didn't help...
end
end
def create
#order = Order.new(exchange_order_params)
if #order.save
#order.update_attributes!(stage: 2, ordered_at: Date.today)
redirect_to admin_returns_url, notice: "Order moved to 'accepted' for processing"
else
flash.now[:alert] = "Please try again"
render :action => "new"
end
end
private
def exchange_order_params
params.require(:order).permit(:id, :user_id,
line_items_attributes: [:id, :order_id, :cart_id, :quantity, :_destroy,
product_attributes: [:id, :sku, :euro_price, :sterling_price, :product_group_id, :product_size_id, :product_waistband_id]])
end
Schema.rb
create_table "orders", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "returned", default: false
t.date "date_sent"
t.date "ordered_at"
t.integer "user_id"
t.boolean "return_requested", default: false
t.integer "stage", default: 0
t.decimal "order_total", default: 0.0
t.string "transaction_secret"
t.string "token"
t.string "uuid"
t.string "currency"
t.float "discounted_by", default: 0.0
end
add_index "line_items", ["cart_id"], name: "index_line_items_on_cart_id", using: :btree
add_index "line_items", ["order_id"], name: "index_line_items_on_order_id", using: :btree
add_index "line_items", ["product_id"], name: "index_line_items_on_product_id", using: :btree
create_table "line_items", force: :cascade do |t|
t.integer "quantity"
t.integer "order_id"
t.integer "cart_id"
t.integer "product_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.float "unit_price"
t.string "currency"
end
create_table "product_groups", force: :cascade do |t|
t.string "name"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "product_sizes", force: :cascade do |t|
t.string "specification"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "product_waistbands", force: :cascade do |t|
t.string "specification"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "products", force: :cascade do |t|
t.integer "sku"
t.integer "product_group_id"
t.integer "product_size_id"
t.integer "product_waistband_id"
t.decimal "euro_price"
t.decimal "sterling_price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "stock_level", default: 0
end
add_index "products", ["product_group_id"], name: "index_products_on_product_group_id", using: :btree
add_index "products", ["product_size_id"], name: "index_products_on_product_size_id", using: :btree
add_index "products", ["product_waistband_id"], name: "index_products_on_product_waistband_id", using: :btree
Also in the Order model I am randomising the id before_create so that when the user submits the form, it creates a dupe copy with a different Order id. This is the same for LineItems.
Order.rb (same in LineItem.rb)
before_create :randomize_id
private
def randomize_id
begin
self.id = SecureRandom.random_number(1_000_000)
end while Order.where(id: self.id).exists?
end
My approach would be to override the ActiveRecord::Base#dup method in the Order model so that it's recursive, meaning that it also duplicates the LineItem collection:
class Order < ActiveRecord::Base
def dup
duped_order = super
duped_order.line_items = line_items.map(&:dup)
duped_order
end
end
doing it this way makes it easily testable. Now the controller becomes:
class OrderController < ApplicationController
def new
#order = Order.find(params[:id]).dup
end
def create
# not sure how your form populates the params hash
# here you need to new-up and then save the order and the line items
# with the attributes from the form
end
end
Do write tests to confirm that this is doing what you intend. This is the perfect example of where the old "fat model skinny controller" paradigm should be applied.

Model as a group that can add other User models

I am having trouble trying to achieve the following, mostly in the controller part:
I have a User model and a Firm model.
A User can create a Firm, this will mean that this user will be the firm owner. Additionally, this user can add other users to join the firm.
So far, my Models are as follows:
class Firm< ActiveRecord::Base
has_many :users, dependent: :destroy
end
class User < ActiveRecord::Base
...
belongs_to :bufete
end
Here is my create action in my firms controller:
def create
#bufete = Bufete.create(bufete_params)
#user = current_user
#bufete.users.create(#user) # Mark that this user belongs to a bufete
#user.owner = true # Mark this user as the owner of the Bufete
respond_to do |format|
if #bufete.save && #user.save
format.html { redirect_to #bufete, :flash => { :success => 'Tu bufete ha sido creado exitosamente.' } }
format.json { render :show, status: :created, location: #bufete }
else
format.html { render 'new', :flash => { :danger => 'Hubo un error al tratar de crear tu bufete.
Porfavor asegurese de que el correo electronico es una direccion valida' } }
format.json { render json: #bufete.errors, status: :unprocessable_entity }
end
end
end
Schema.rb file:
ActiveRecord::Schema.define(version: 20150730061404) do
create_table "bufetes", force: :cascade do |t|
t.string "name"
t.string "address"
t.string "telephone"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "description"
t.string "code"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "admin", default: false
t.boolean "premium", default: false
t.integer "bufete_id"
t.string "name"
t.string "last_name"
t.boolean "owner", default: false
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
I believe my associations are correct, but I could be mistaken. My main problem is in the controller. When a user creates a firm, how do I assign this user to be the owner of this Firm? At the same time how do I add this user to the Firm.users collection?
Also, how would I go for adding future users to a specific firm's users collection?
Important: A user can only create ONE Firm. At the same time, a user can only belong to ONE firm as well. If a user creates a firm, it will belong to THAT firm.
I assume Bufete is equal to Firm model, in the code below I'll use Bufete instead of Firm. You can check whether the user can create a new Bufete before creating the Bufete record.
def create
#user = current_user
if #user.can_create_bufete?
#bufete = Bufete.create(bufete_params)
# assign user to #bufete instead of #bufete.users.create()
#user.bufete = #bufete
#user.owner = true
# add your response_to block for #user.saved
else
# add your response_to block of not creating new Bufete
end
end
Then you'll check whether the user can create a Bufete object or not in your User model.
def can_create_bufete?
!owner && !bufete.present? # or any condition that meets your requirement
end

Resources