The user can choose of one of two submit buttons. If he clicks <%= f.submit :conceal %> how can the default value be made to change from false to true?
t.boolean "conceal", default: false
because right now if the user clicks the button - the default value remains false:
[1] pry(main)> Valuation.find(9)
Valuation Load (0.2ms) SELECT "valuations".* FROM "valuations" WHERE "valuations"."id" = ? LIMIT 1 [["id", 9]]
=> #<Valuation:0x007fdf26c736b8
id: 9,
conceal: false,
user_id: 1,
created_at: Thu, 23 Apr 2015 16:21:31 UTC +00:00,
updated_at: Thu, 23 Apr 2015 16:21:31 UTC +00:00,
likes: nil,
name: "Conceal/Private/Hide">
This didn't work <%= f.submit :conceal => true %>.
class ValuationsController < ApplicationController
before_action :set_valuation, only: [:show, :edit, :update, :destroy, :like]
before_action :logged_in_user, only: [:create, :destroy]
def index
if params[:tag]
#valuations = Valuation.tagged_with(params[:tag])
else
#valuations = Valuation.order('RANDOM()')
end
end
def show
#valuation = Valuation.find(params[:id])
#commentable = #valuation
#comments = #commentable.comments
#comment = Comment.new
end
def new
#valuation = current_user.valuations.build
end
def edit
end
def create
#valuation = current_user.valuations.build(valuation_params)
if #valuation.save
track_activity #valuation
redirect_to #valuation, notice: 'Value was successfully created'
else
#feed_items = []
render 'pages/home'
end
end
def update
if #valuation.update(valuation_params)
track_activity #valuation
redirect_to #valuation, notice: 'Value was successfully updated'
else
render action: 'edit'
end
end
def destroy
#valuation.destroy
redirect_to valuations_url
end
def like
without_tracking do
#valuation.increment!(:likes)
end
#valuation.create_activity :like
flash[:success] = 'Thanks for sharing your Value!'
redirect_to valuation_path(#valuation)
end
private
def without_tracking
Valuation.public_activity_off
yield if block_given?
Valuation.public_activity_on
end
def set_valuation
#valuation = Valuation.find(params[:id])
end
def correct_user
#valuation = current_user.valuations.find_by(id: params[:id])
redirect_to valuations_path, notice: "Not authorized to edit this valuation" if #valuation.nil?
end
def valuation_params
params.require(:valuation).permit(:name, :conceal, :tag_list, :content, :commentable, :comment, :like)
end
end
UPDATE
Started POST "/valuations" for 127.0.0.1 at 2015-04-23 15:27:35 -0400
Processing by ValuationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Xd4ISNLZxjryLJfxvauWUANBzJthCNBzUwhtxseB/ird77mdYoKY/f9Skzb68lClaWOIUJXie9qC0jI1l+d98w==", "valuation"=>{"name"=>"PRIVATE AGAIN", "tag_list"=>""}, "commit"=>"conceal"}
[1m[36mUser Load (0.7ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1[0m [["id", 1]]
[1m[35mHabit Load (0.2ms)[0m SELECT "habits".* FROM "habits" WHERE "habits"."user_id" = ? [["user_id", 1]]
[1m[36mHabit Load (0.2ms)[0m [1mSELECT "habits".* FROM "habits"[0m
[1m[35mActsAsTaggableOn::Tag Load (0.2ms)[0m SELECT "tags".* FROM "tags" WHERE (LOWER(name) = LOWER('ingrain'))
[1m[36m (0.1ms)[0m [1mbegin transaction[0m
[1m[35mSQL (31.7ms)[0m INSERT INTO "valuations" ("name", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "PRIVATE AGAIN"], ["user_id", 1], ["created_at", "2015-04-23 19:27:36.015267"], ["updated_at", "2015-04-23 19:27:36.015267"]]
[1m[36mActsAsTaggableOn::Tag Load (0.1ms)[0m [1mSELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = ? AND "taggings"."taggable_type" = ? AND (taggings.context = 'tags' AND taggings.tagger_id IS NULL)[0m [["taggable_id", 15], ["taggable_type", "Valuation"]]
[1m[35m (10.8ms)[0m commit transaction
[1m[36m (0.1ms)[0m [1mbegin transaction[0m
[1m[35mSQL (1.7ms)[0m INSERT INTO "activities" ("action", "trackable_id", "trackable_type", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?) [["action", "create"], ["trackable_id", 15], ["trackable_type", "Valuation"], ["user_id", 1], ["created_at", "2015-04-23 19:27:36.136688"], ["updated_at", "2015-04-23 19:27:36.136688"]]
[1m[36m (1.5ms)[0m [1mcommit transaction[0m
Redirected to http://0.0.0.0:3000/valuations/15
The submit method takes an argument for what name it will show up as, but that's only useful for determining which button, if there's more than one, was used to submit the form.
What you want to do is introduce a hidden field that has the right naming convention so you can use update_attributes, or you need to test for the presence of params[:commit] which, if present, means someone pressed that button:
if (params[:commit] == 'conceal')
#valuation.conceal = true
end
Related
I'm trying to setup multiple tagging in my app. I have used a single tag and tagging model which works fine for tagging a single model.
However, after setting up the association, i got this error when i wanted to create a new question undefined method map for nil:NilClass which actually points to <%= select_tag(:kategory_id, options_for_select(#kategories), :prompt => "Select Category", class: "form-control") %>. I don't know why it's pointing to this since it has nothing to do with the tagging. I might have made a mistake somewhere which i could not figure out.
Here is how i do the setup.
I added taggable_id and taggable_type to taggings table.
class AddAttributesToTaggings < ActiveRecord::Migration[5.1]
def change
add_column :taggings, :taggable_id, :integer
add_column :taggings, :taggable_type, :string
add_index :taggings, [:taggable_type, :taggable_id]
end
end
Tag.rb
class Tag < ApplicationRecord
has_many :taggings
has_many :posts, through: :taggings, source: :taggable, source_type: Post
has_many :questions, through: :taggings, source: :taggable, source_type: Question
has_many :user_tags, dependent: :destroy
has_many :users, through: :user_tags
extend FriendlyId
friendly_id :name, use: :slugged
def should_generate_new_friendly_id?
name_changed?
end
end
tagging.rb
class Tagging < ApplicationRecord
belongs_to :tag
belongs_to :taggable, :polymorphic => true
end
Question.rb
class Question < ApplicationRecord
belongs_to :user
belongs_to :kategory
validates :title, :content, presence: true
is_impressionable counter_cache: true, unique: :all
Question.order('impressions_count DESC')
scope :most_recent, -> { order(created_at: :desc) }
extend FriendlyId
friendly_id :title, use: :slugged
def should_generate_new_friendly_id?
title_changed?
end
include Taggable
def related_questions
Question.joins(:tags).where(tags: { id: self.tags.pluck(:id) }).where.not(id: self.id)
end
end
models/concerns/taggable.rb
module Taggable
extend ActiveSupport::Concern
included do
has_many :taggings, :as => :taggable
has_many :tags, :through => :taggings
end
def tag_list
self.tags.collect do |tag|
tag.name
end.join(", ")
end
def tag_list=(tags_string)
tag_names = tags_string.split(",").collect{|s| s.strip.downcase}.uniq
new_or_found_tags = tag_names.collect { |name| Tag.friendly.find_or_create_by(name: name) }
self.tags = new_or_found_tags
end
end
tags and taggings table in schema.rb
create_table "taggings", force: :cascade do |t|
t.bigint "tag_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "taggable_id"
t.string "taggable_type"
t.index ["tag_id"], name: "index_taggings_on_tag_id"
t.index ["taggable_type", "taggable_id"], name: "index_taggings_on_taggable_type_and_taggable_id"
end
create_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.index ["slug"], name: "index_tags_on_slug", unique: true
end
questions/_form
<%= form_with(model: question, local: true) do |form| %>
<% if question.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(question.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul>
<% question.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<b><%= form.label "Category" %></b>
<%= select_tag(:kategory_id, options_for_select(#kategories), :prompt => "Select Category", class: "form-control") %>
</div>
<br>
<div class="field">
<b><%= form.label :title %></b>
<%= form.text_field :title, id: :question_title, class: "form-control" %>
</div>
<br>
<div class="field">
<%= form.label :content %>
<%= form.text_area :content, id: :question_content, class: "form-control" %>
</div>
<br>
<div>
<%= form.label :tag_list %>
<%= form.text_field :tag_list %>
</div>
<br>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
questions_controller.rb
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
before_action :find_contacts
before_action :find_kategory
impressionist :actions=>[:show,:index]
# GET /questions
# GET /questions.json
def index
if params[:kategory].blank?
#questions = Question.most_recent
else
#kategory_id = Kategory.find_by(name: params[:kategory]).id
#questions = Question.where(:kategory_id => #kategory_id).most_recent
end
end
# GET /questions/1
# GET /questions/1.json
def show
impressionist(#question)
#most_viewed = Question.order('impressions_count DESC').take(20)
end
# GET /questions/new
def new
#question = current_user.questions.build
#kategories = Kategory.all.map{ |k| [k.name, k.id] }
end
# GET /questions/1/edit
def edit
#kategories = Kategory.all.map{ |k| [k.name, k.id] }
end
# POST /questions
# POST /questions.json
def create
#question = current_user.questions.build(question_params)
#question.kategory_id = params[:kategory_id]
respond_to do |format|
if #question.save
flash[:success] = 'Your question was successfully posted.'
format.html { redirect_to #question }
format.json { render :show, status: :created, location: #question }
else
format.html { render :new }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /questions/1
# PATCH/PUT /questions/1.json
def update
respond_to do |format|
if #question.update(question_params)
flash[:success] = 'Your question was successfully updated.'
format.html { redirect_to #question }
format.json { render :show, status: :ok, location: #question }
else
format.html { render :edit }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# DELETE /questions/1
# DELETE /questions/1.json
def destroy
#question.destroy
respond_to do |format|
flash[:success] = 'Your question has been deleted.'
format.html { redirect_to questions_url }
format.json { head :no_content }
end
end
def most_viewed
#questions = Question.order('impressions_count DESC').take(20)
end
private
# Use callbacks to share common setup or constraints between actions.
def set_question
#question = Question.friendly.includes(:tags).find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def question_params
params.require(:question).permit(:title, :content, :kategory_id, :tag_list)
end
def find_contacts
#contacts = user_signed_in? ? current_user.all_active_contacts : ''
end
def find_kategory
#questions = Kategory.where(:kategory_id => #kategory_id)
end
end
UPDATE:**I'm now able to save a question without adding any tag but with tags added, I get a form error that tagging is invalid. **Tags are properly loaded when I edit a question.
Error Log:
Started POST "/questions" for 127.0.0.1 at 2018-07-13 12:01:01 +0100
Processing by QuestionsController#create as HTML
Parameters: {"utf8"=>"√", "authenticity_token"=>"hgLn8bzd6fVSzCIPtRd3P0Jp/LEso
/h5cKNBY0a80x3i4RF6tpLlRyqmls3xRFryqyP1/s/rLDVIt9C1/uK+qw==", "kategory_id"=>"1"
, "question"=>{"title"=>"Help!!! My Dell Inspiron 6400 is hanging", "content"=>"
Lorem ipsum dolor amet seitan offal ethical, beard viral lo-fi put a bird on it
salvia actually yr. Ethical ennui pitchfork fanny pack, gentrify seitan sartoria
l bespoke. Viral 90's church-key swag, you probably haven't heard of them banh m
i intelligentsia brunch DIY iceland wolf pitchfork. Everyday carry photo booth n
ormcore XOXO tumblr portland.\r\n\r\nBrooklyn heirloom kombucha, edison bulb leg
gings hell of DIY chartreuse austin tacos bitters. Blog hexagon copper mug blue
bottle cray. Post-ironic direct trade kale chips mumblecore. Craft beer squid cr
onut vape, hoodie bitters succulents ramps snackwave vegan small batch brunch ch
ia food truck umami. Chillwave blue bottle viral raclette authentic health goth
vape coloring book cardigan 3 wolf moon taxidermy. Gluten-free tote bag hella, l
omo pinterest direct trade gastropub tattooed. Iceland hammock post-ironic, bush
wick cornhole tumeric dreamcatcher blog palo santo chartreuse 90's food truck sy
nth chicharrones.", "tag_list"=>"hardware"}, "commit"=>"Create Question"}
User Load (2.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDE
R BY "users"."id" ASC LIMIT $2 [["id", 3], ["LIMIT", 1]]
Private::Conversation Load (2.9ms) SELECT "private_conversations".* FROM "pri
vate_conversations" WHERE ("private_conversations"."recipient_id" = $1 OR "priva
te_conversations"."sender_id" = $2) [["recipient_id", 3], ["sender_id", 3]]
Private::Message Load (2.0ms) SELECT "private_messages".* FROM "private_messa
ges" WHERE "private_messages"."conversation_id" IN (2, 3, 4, 6)
Group::Conversation Load (3.9ms) SELECT "group_conversations".* FROM "group_c
onversations" INNER JOIN "group_conversations_users" ON "group_conversations"."i
d" = "group_conversations_users"."conversation_id" WHERE "group_conversations_us
ers"."user_id" = $1 [["user_id", 3]]
Group::Message Load (2.0ms) SELECT "group_messages".* FROM "group_messages" W
HERE "group_messages"."conversation_id" = 1
User Load (2.0ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (2, 3,
5)
(40.0ms) SELECT "group_conversations"."id" FROM "group_conversations" INNER
JOIN "group_conversations_users" ON "group_conversations"."id" = "group_conversa
tions_users"."conversation_id" WHERE "group_conversations_users"."user_id" = $1
[["user_id", 3]]
CACHE (0.0ms) SELECT "group_conversations"."id" FROM "group_conversations" I
NNER JOIN "group_conversations_users" ON "group_conversations"."id" = "group_con
versations_users"."conversation_id" WHERE "group_conversations_users"."user_id"
= $1 [["user_id", 3]]
User Load (2.9ms) SELECT "users".* FROM "users" INNER JOIN "contacts" ON "use
rs"."id" = "contacts"."contact_id" WHERE "contacts"."user_id" = $1 AND "contacts
"."accepted" = $2 [["user_id", 3], ["accepted", "t"]]
User Load (4.9ms) SELECT "users".* FROM "users" INNER JOIN "contacts" ON "use
rs"."id" = "contacts"."user_id" WHERE "contacts"."contact_id" = $1 AND "contacts
"."accepted" = $2 ORDER BY "users"."created_at" ASC [["contact_id", 3], ["accep
ted", "t"]]
Tag Load (2.0ms) SELECT "tags".* FROM "tags" WHERE "tags"."name" = $1 LIMIT
$2 [["name", "hardware"], ["LIMIT", 1]]
Kategory Load (10.7ms) SELECT "kategories".* FROM "kategories"
(1.0ms) BEGIN
Question Exists (4.9ms) SELECT 1 AS one FROM "questions" WHERE ("questions".
"id" IS NOT NULL) AND "questions"."slug" = $1 LIMIT $2 [["slug", "help-my-dell-
inspiron-6400-is-hanging"], ["LIMIT", 1]]
Kategory Load (5.9ms) SELECT "kategories".* FROM "kategories" WHERE "kategor
ies"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
(0.0ms) ROLLBACK
Rendering questions/new.html.erb within layouts/application
Rendered questions/_form.html.erb (17.6ms)
Rendered questions/new.html.erb within layouts/application (141.6ms)
Rendered layouts/navigation/header/_toggle_button.html.erb (1.0ms)
Rendered layouts/navigation/header/_home_button.html.erb (30.3ms)
User Load (28.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIM
IT $2 [["id", 5], ["LIMIT", 1]]
Rendered layouts/navigation/header/dropdowns/conversations/_private.html.erb (
73.2ms)
User Load (2.9ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMI
T $2 [["id", 3], ["LIMIT", 1]]
CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $
1 LIMIT $2 [["id", 5], ["LIMIT", 1]]
Rendered layouts/navigation/header/dropdowns/conversations/_private.html.erb (
109.4ms)
Rendered layouts/navigation/header/dropdowns/conversations/_group.html.erb (3.
9ms)
User Load (30.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIM
IT $2 [["id", 1], ["LIMIT", 1]]
Rendered layouts/navigation/header/dropdowns/conversations/_private.html.erb (
40.0ms)
CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $
1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
User Load (2.9ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMI
T $2 [["id", 2], ["LIMIT", 1]]
Rendered layouts/navigation/header/dropdowns/conversations/_private.html.erb (
100.6ms)
Rendered layouts/navigation/header/dropdowns/_conversations.html.erb (983.4ms)
User Load (2.0ms) SELECT "users".* FROM "users" INNER JOIN "contacts" ON "use
rs"."id" = "contacts"."user_id" WHERE "contacts"."contact_id" = $1 AND "contacts
"."accepted" = $2 [["contact_id", 3], ["accepted", "f"]]
Rendered layouts/navigation/header/dropdowns/contact_requests/_no_requests.htm
l.erb (1.0ms)
Rendered layouts/navigation/header/dropdowns/_contact_requests.html.erb (374.0
ms)
Rendered layouts/navigation/header/_dropdowns.html.erb (1713.9ms)
Rendered layouts/navigation/_header.html.erb (2485.4ms)
Kategory Load (2.9ms) SELECT "kategories".* FROM "kategories"
Rendered layouts/navigation/collapsible_elements/_constant_links.html.erb (2.0
ms)
(2.0ms) SELECT COUNT(*) FROM "questions" INNER JOIN "save_questions" ON "que
stions"."id" = "save_questions"."question_id" WHERE "save_questions"."user_id" =
$1 [["user_id", 3]]
Rendered layouts/navigation/collapsible_elements/_signed_in_links.html.erb (21
.5ms)
Rendered layouts/navigation/_collapsible_elements.html.erb (543.0ms)
Rendered layouts/_navigation.html.erb (3323.2ms)
Rendered layouts/application/_private_conversations_windows.html.erb (1.0ms)
Rendered layouts/application/_group_conversations_windows.html.erb (2.0ms)
Completed 200 OK in 22203ms (Views: 21796.6ms | ActiveRecord: 158.2ms)
You need to define #kategories = Kategory.all.map{ |k| [k.name, k.id] } in create and update actions. This actions rerender new/edit actions if they can't save the question, and they need #kategories for rerendering
If you provide the full server log for create action I can try to help you to figure out - why #question can not be saved
Looks to me like your #kategories, or something within there (perhaps a name), is nil, hence the error :) (Hopefully this is a good thing, as all may be well with your tagging.)
Ensure Kategory.all.map { |k| [k.name, k.id] } in your new action is returning records and this error should go away.
N.B. you can also use options_from_collection_for_select here.
# in the controller
def new
#question = current_user.questions.build
#kategories = Kategory.all
end
# and the view
<%= select_tag(:kategory_id, options_from_collection_for_select(#kategories, :name, :id), prompt: "Select Category", class: "form-control") %>
This way, if you don't have any categories, you won't get an error - instead, you just won't have any options available.
I have a problem with my small app build in Rails 5.
The project have only 4 tables: User, Custom, Contact, ContactCustom
The idea is an User register his customs fields and when he is going to add new contacts, the form should show the customs of the User logged in.
My problem is when I try to register a new contact with the customs of the user logged in, I have a n+1 inserting a nil register in ContactCustom table and don't catch the custom_id that I pass with a hidden_field.
My models are like this:
class Custom < ApplicationRecord
belongs_to :user
belongs_to :kind
has_many :contact_customs
has_many :contacts, through: :contact_customs
end
class ContactCustom < ApplicationRecord
belongs_to :contact, optional: true
belongs_to :custom, optional: true
accepts_nested_attributes_for :custom
end
class Contact < ApplicationRecord
belongs_to :user
has_many :contact_customs
has_many :customs, through: :contact_customs
accepts_nested_attributes_for :contact_customs
end
and here my contact_controller:
class ContactsController < ApplicationController
before_action :set_contact, only: [:show, :edit, :update, :destroy]
before_action :set_user_and_custom, only: [ :new, :create, :edit ]
def index
#contacts = Contact.all
end
def show
end
def new
#contact = Contact.new
#contact.contact_customs.build
end
def edit
end
def create
#contact = Contact.new(contact_params)
#contact.contact_customs.build
#binding pry
respond_to do |format|
if #contact.save
format.html { redirect_to #contact, notice: 'Contact was successfully created.' }
format.json { render :show, status: :created, location: #contact }
else
format.html { render :new }
format.json { render json: #contact.errors, status: :unprocessable_entity }
end
end
end
private
def set_contact
#contact = Contact.find(params[:id])
end
def set_user_and_custom
#user = current_user
#usercustom = Custom.where(user_id: #user)
end
def contact_params
params.require(:contact).permit(:email, :name, :user_id,
contact_customs_attributes: [ :id, :value, :custom_id, custom_attributes: [] ])
end
end
and here is my form ... I think that I made something wrong with the each loop:
<% #usercustom.each do |c| %>
<%= f.fields_for :contact_customs do |cc| %>
<div class="field">
<%= cc.label :value, c.name %>
<%= cc.text_field :value %>
</div>
<%= cc.fields_for :custom do |custom| %>
<%= custom.text_field :id, value: c.id %>
<% end %>
<% end %>
<% end %>
I don't know how to show how many custom fields as necessary without this loop and my query ~> #usercustom = Custom.where(user_id: #user) is registering one more nil record(n+1).
Here is the log message when I submit the contact form with only one custom record at Custom table:
Started POST "/contacts" for 127.0.0.1 at 2017-03-17 09:14:02 -0300
Processing by ContactsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"nIlwxH4Ua8DjAKkMpGh8B7nxwYf6gy1Fhkdh1PaMtSANx5sB6YaOKbBUekQ4M3KP56WuHgsX31iHq2lj4+fEwA==", "contact"=>{"email"=>"test#test", "name"=>"name test", "user_id"=>"1", "contact_customs_attributes"=>{"0"=>{"value"=>"custom test"}}}, "commit"=>"Create Contact"}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
(0.2ms) BEGIN
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
SQL (108.3ms) INSERT INTO "contacts" ("email", "name", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["email", "test#test"], ["name", "name test"], ["user_id", 1], ["created_at", 2017-03-17 12:14:02 UTC], ["updated_at", 2017-03-17 12:14:02 UTC]]
SQL (7.7ms) INSERT INTO "contact_customs" ("value", "contact_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["value", "custom test"], ["contact_id", 3], ["created_at", 2017-03-17 12:14:02 UTC], ["updated_at", 2017-03-17 12:14:02 UTC]]
SQL (0.6ms) INSERT INTO "contact_customs" ("contact_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["contact_id", 3], ["created_at", 2017-03-17 12:14:02 UTC], ["updated_at", 2017-03-17 12:14:02 UTC]]
(36.5ms) COMMIT
Redirected to http://localhost:3000/contacts/3
Completed 302 Found in 176ms (ActiveRecord: 154.5ms)
Try to comment or remove #contact.contact_customs.build from you create action. That is the reason you have an N+1 contact_customs with all the fields = nil.
When you do #contact = Contact.new(contact_params) you create a #contact that should look like this:
#contact = Contact.new(:email => contact_params[:email], :name => contact_params[:name], ..etc..., :custom_attributes => contact_customs_attributes: [ :id, :value, :custom_id, custom_attributes: [] ])
With that you have a #contact object instantiated and as array:
#contact.contact_customs = [ first_contact_custom => [firstvalue, secondvalue], second_contact_custom => [firstvalue, secondvalue]]
The following:
#contact.contact_customs.build
is like doing
#custom = Custom.new()
#contact.customs << #custom
Which will append that #custom entry with all fields = nil in the join table contact_customs.
#contact.contact_customs = [ first_contact_custom => [firstvalue, secondvalue], second_contact_custom => [firstvalue, secondvalue], second_contact_custom => [nil, nil] ]
So try remove the following line
#contact.contact_customs.build
The only place where you need that line is in the new action, because you need those fields instantiated for the form.
I have Product model with some params (price, category_id, image etc.).
When creating a new product in the form partial, category is being selected via select_tag and image gets uploaded via Carrierwave, image uploader. Bad things happens when I send user to crop the uploaded image in crop.html.erb file. There user crops image, clicks submit, which uses path as update (not very sure which HTTP protocol), and gets redirected into product edit page, since product somehow lost category_id parameter. Form shows error to select a category (all other params from input_fields does not get lost).
My tries was like defining the crop method and setting category there, but no luck...
products_controller.rb:
def edit
#categories = Category.all
end
def create
#product = Product.new(product_params)
#product.category_id = params[:category_id]
#product.user_id = current_user.id
respond_to do |format|
if #product.save
if params[:product][:image].present?
format.html { render :crop }
else
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
end
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
def update
#product.category_id = params[:category_id]
respond_to do |format|
if #product.update(product_params)
if params[:product][:image].present?
format.html { render :crop }
else
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: #product }
#products = Product.all
ActionCable.server.broadcast 'products',
html: render_to_string('store/index', layout: false)
end
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
crop.html.erb (in products folder):
<%= image_tag #product.image_url(:large), id: "cropbox" %>
<h4>Preview</h4>
<div style="width:300px; height:200px; overflow:hidden;">
<%= image_tag #product.image.url(:large), :id => "preview" %>
</div>
<%= form_for #product do |f| %>
<% %w[x y w h].each do |attribute| %>
<%= f.hidden_field "crop_#{attribute}" %>
<% end %>
<div class="actions">
<%= f.submit "Crop" %>
</div>
<% end %>
I haven't tried to set a callback that stores category_id, but I wonder would it be a good idea? Any help? Thanks!
EDIT - also adding a form partial, but it works fine - just for your curiosity:
<%= form_for(product, hmtl: { multipart: true } ) do |f| %>
...
<div class="field">
<%= f.label :category %>
<%= select_tag(:category_id, options_from_collection_for_select(Category.all, :id, :name, #product.category_id), include_blank: "Select Category") %>
</div>
UPDATE
Logs for these actions:
Started GET "/products/new" for ::1 at 2016-12-15 09:03:31 +0200
Processing by ProductsController#new as HTML
[1m[36mCart Load (0.4ms)[0m [1m[34mSELECT "carts".* FROM "carts" WHERE "carts"."id" = $1 LIMIT $2[0m [["id", 5], ["LIMIT", 1]]
[1m[36mCACHE (0.0ms)[0m [1m[34mSELECT "carts".* FROM "carts" WHERE "carts"."id" = $1 LIMIT $2[0m [["id", 5], ["LIMIT", 1]]
[1m[36mUser Load (2.0ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2[0m [["id", 1], ["LIMIT", 1]]
Rendering products/new.html.erb within layouts/application
[1m[36mCategory Load (0.4ms)[0m [1m[34mSELECT "categories".* FROM "categories"[0m
Rendered products/_form.html.erb (6.2ms)
Rendered products/new.html.erb within layouts/application (11.2ms)
[1m[36mCACHE (0.0ms)[0m [1m[34mSELECT "categories".* FROM "categories"[0m
[1m[36mLineItem Load (0.5ms)[0m [1m[34mSELECT "line_items".* FROM "line_items" WHERE "line_items"."cart_id" = $1[0m [["cart_id", 5]]
Completed 200 OK in 127ms (Views: 113.2ms | ActiveRecord: 3.3ms)
Started POST "/products" for ::1 at 2016-12-15 09:03:40 +0200
Processing by ProductsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"eWZuqL6AqcN8wknjEL115ax9uBnpY4b9eP0o2xN2aPntd61YKyc4Ym1lUgjV1YrXfZbPr57HANXy7Kz5swCtlg==", "product"=>{"title"=>"kj", "description"=>"kj", "image"=>#<ActionDispatch::Http::UploadedFile:0x007fe40ba4abe0 #tempfile=#<Tempfile:/var/folders/dn/zq9x2jkd4856kwhfj5gbz2tc0000gn/T/RackMultipart20161215-3987-1adfacs.png>, #original_filename="Screen Shot 2016-12-05 at 09.14.48.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"product[image]\"; filename=\"Screen Shot 2016-12-05 at 09.14.48.png\"\r\nContent-Type: image/png\r\n">, "price"=>"98", "quantity"=>"98"}, "category_id"=>"1", "commit"=>"Create Product"}
[1m[36mCart Load (0.3ms)[0m [1m[34mSELECT "carts".* FROM "carts" WHERE "carts"."id" = $1 LIMIT $2[0m [["id", 5], ["LIMIT", 1]]
[1m[36mCACHE (0.0ms)[0m [1m[34mSELECT "carts".* FROM "carts" WHERE "carts"."id" = $1 LIMIT $2[0m [["id", 5], ["LIMIT", 1]]
[1m[36mUser Load (0.7ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2[0m [["id", 1], ["LIMIT", 1]]
[1m[35m (0.3ms)[0m [1m[35mBEGIN[0m
[1m[36mCategory Load (0.3ms)[0m [1m[34mSELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT $2[0m [["id", 1], ["LIMIT", 1]]
[1m[35mSQL (1.0ms)[0m [1m[32mINSERT INTO "products" ("title", "description", "price", "quantity", "created_at", "updated_at", "category_id", "user_id", "image") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id"[0m [["title", "kj"], ["description", "kj"], ["price", #<BigDecimal:7fe40ccf9110,'0.98E2',9(18)>], ["quantity", 98], ["created_at", 2016-12-15 07:03:41 UTC], ["updated_at", 2016-12-15 07:03:41 UTC], ["category_id", "1"], ["user_id", 1], ["image", "Screen_Shot_2016-12-05_at_09.14.48.png"]]
[1m[35m (3.1ms)[0m [1m[35mCOMMIT[0m
Rendering products/crop.html.erb within layouts/application
Rendered products/crop.html.erb within layouts/application (3.1ms)
[1m[36mCategory Load (0.7ms)[0m [1m[34mSELECT "categories".* FROM "categories"[0m
[1m[36mLineItem Load (0.3ms)[0m [1m[34mSELECT "line_items".* FROM "line_items" WHERE "line_items"."cart_id" = $1[0m [["cart_id", 5]]
Completed 200 OK in 957ms (Views: 127.8ms | ActiveRecord: 6.7ms)
So I noticed that it renders products/crop.html.erb without a particular ID, so I added in my routes:
resources :products do
get 'crop', on: :member
end
And products_controller create action:
...
respond_to do |format|
if #product.save
if params[:product][:image].present?
format.html { render crop_product_path(#product) }
else
...
Still the same error, that a category must be selected.
And to note - if simply go to edit product (but not from the crop action), category sits there as supposed...
Since form only submits the parameters gathered which are defined in it, you should add a hidden field to set the category_id in crop.html view
<%= image_tag #product.image_url(:large), id: "cropbox" %>
<h4>Preview</h4>
<div style="width:300px; height:200px; overflow:hidden;">
<%= image_tag #product.image.url(:large), :id => "preview" %>
</div>
<%= form_for #product do |f| %>
<% %w[x y w h].each do |attribute| %>
<%= f.hidden_field "crop_#{attribute}" %>
<% end %>
<%= f.hidden_field :category_id %>
<div class="actions">
<%= f.submit "Crop" %>
</div>
<% end %>
Now, when you submit the form, you will receive category_id on server in params[:product][:category_id]
I got a model day and a model task. day has many tasks. I'm using a nested_form for this. The user enters a time and two variables, which a caculated to an index. The first task, with the highest index has a starttime= 8am.
Now I want to order the tasks by the index and add every task's time to the previous task's starttime.
My attempt to solve this:
def create
#day = current_user.days.build(day_params)
#day.save
#day.tasks.each do |task|
task.index = task.ur**2 + task.imp
end
if current_user.worktype = 1
#tasks = #day.tasks.order(index: :desc)
x = 0
#tasks.each do |task|
if x = 0
task.starttime = Time.new.beginning_of_day + 8*60*60
x = task.id
else
task.starttime = #day.task.find(x).starttime + #day.task.find(x).time*60
x = task.id
end
end
elsif current_user.worktype = 2
...
end
#day.save
respond_to do |format|
if #day.save
format.html { redirect_to #day, notice: 'Day was successfully created.' }
format.json { render :show, status: :created, location: #day }
else
format.html { render :new }
format.json { render json: #day.errors, status: :unprocessable_entity }
end
end
end
But somehow starttime remains nil, when I want to print it out in the view
- #tasks.each do |task|
...
= task.starttime.strftime("%H:%M")
I checked it in rails console too.
consolelog for POST:
Started POST "/days" for ::1 at 2016-08-04 02:19:03 +0200
Processing by DaysController#create as HTML
Parameters: {"utf8"=>"V", "authenticity_token"=>"YaLq2XBUMltzCpZxvKBp5NQGUgiw/Ockto1r0zy/dZHU3HVlp4lpcsH/b3Q9WYas97ENlwRiPzCUdOiBC06GbA==", "day"=>{"tasks_attributes"=>{"1470269934695"=> {"description"=>"1", "ur"=>"1", "imp"=>"1", "time"=>"1"
, "_destroy"=>"false"}, "1470269939280"=>{"description"=>"2", "ur"=>"3", "imp"=>"3", "time"=>"2", "_destroy"=>"false"}}}, "commit"=>"Create Day"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
(0.0ms) begin transaction
SQL (3.5ms) INSERT INTO "days" ("user_id", "created_at", "updated_at") VALUES (?, ?, ?) [["user_id", 1], ["created_at", "2016-08-04 00:19:03.986762"], ["updated_at", "2016-08-04 00:19:03.986762"]]
SQL (0.0ms) INSERT INTO "tasks" ("description", "ur", "imp", "time", "day_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) [["description", "1"], ["ur", 1], ["imp", 1], ["time", 1], ["day_id", 11], ["created_at", "2016-08-04 00:19:03.992775"], ["updated_at", "2016-08-04 00:19:03.992775"]]
SQL (0.0ms) INSERT INTO "tasks" ("description", "ur", "imp", "time", "day_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) [["description", "2"], ["ur", 3], ["imp", 3], ["time", 2], ["day_id", 11], ["created_at", "2016-08-04 00:19:03.994776"], ["updated_at", "2016-08-04 00:19:03.994776"]]
(4.0ms) commit transaction
Task Load (0.5ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."day_id" = ? [["day_id", 11]]
Task Load (0.5ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."day_id" = ? ORDER BY "tasks"."index" DESC [["day_id", 11]]
(0.0ms) begin transaction
SQL (1.0ms) UPDATE "tasks" SET "index" = ?, "updated_at" = ? WHERE "tasks"."id" = ? [["index", 2], ["updated_at", "2016-08-04 00:19:04.006796"], ["id", 24]]
SQL (1.0ms) UPDATE "tasks" SET "index" = ?, "updated_at" = ? WHERE "tasks"."id" = ? [["index", 12], ["updated_at", "2016-08-04 00:19:04.009792"], ["id", 25]]
(3.6ms) commit transaction
(0.0ms) begin transaction
(0.0ms) commit transaction
Redirected to http://localhost:3000/days/11
Completed 302 Found in 39ms (ActiveRecord: 14.6ms)
EDIT
Building on #evanbike's answer I added a task.save everytime starttime is set. But nothing changed, so I tried and removed the If statement and now starttime is saved, but every task has the same time.
#tasks = #day.tasks.order(index: :desc)
x = 0
#tasks.each do |task|
if x = 0
task.starttime = Time.new.beginning_of_day + 8*60*60
task.save
x = task.id
else
task.starttime = #day.task.find(x).starttime + #day.task.find(x).time*60
task.save
x = task.id
end
end
#day.save
I hope someone can help me with this issue.
Thanks in advance.
When you do this, you are setting the index on the instance of the task in the #day association cache:
#day.tasks.each do |task|
task.index = task.ur**2 + task.imp
end
Then, when you do this:
#tasks = #day.tasks.order(index: :desc)
...it makes a db call (since you're calling order on it) and return new instances—that don't have index set. If you called sort or some array method, it would use the stored instances
I think the simplest would be to save the instances of tasks after you set each of the values. Calling sort on the association would probably work, but it seems brittle.
I want to use find_or_create method in my game dates controller. I don't know how to use that method in create action, when params are in game_date_params. Any suggestion how can I extract date from game_date_params?
class GameDatesController < ApplicationController
before_action :authenticate_user!
before_action :authenticate_admin
def index
#game_dates = GameDate.all
#showcases = Showcase.joins(:game_dates)
end
def new
#game_date = GameDate.new
#game_date.referee_stats.build
end
def create
#game_date = GameDate.new(game_date_params)
if #game_date.save
redirect_to showcases_path
flash[:success] = "Game date created"
else
render 'new'
end
end
def show
#game_date = GameDate.find(params[:id])
end
def destroy
#game_date = GameDate.find(params[:id]).destroy
redirect_to root_url
flash[:success] = "Game date deleted"
end
private
def game_date_params
params.require(:game_date).permit(:date, referee_stats_attributes: [ :games_count, :showcase_id ])
end
This is output from POST action:
Started POST "/game_dates" for 127.0.0.1 at 2016-04-01 10:21:44 +0200
Processing by GameDatesController#create as HTML Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"jmuOmMCO/WTFIkxrsw5l2cPVMqZAl7h11f281I+OyoHH3ddwKoB9ANAqvQEHulR88c7fzQXnnIaxs8FChMCjqw==",
"game_date"=>{"date(1i)"=>"2016", "date(2i)"=>"4", "date(3i)"=>"1",
"referee_stats_attributes"=>{"0"=>{"games_count"=>"4",
"showcase_id"=>"1"}}}, "commit"=>"Create Game date"} User Load
(0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER
BY "users"."id" ASC LIMIT 1 [["id", 1]] GameDate Load (0.4ms)
SELECT "game_dates".* FROM "game_dates" WHERE "game_dates"."date" IS
NULL LIMIT 1 (0.2ms) BEGIN SQL (0.4ms) INSERT INTO "game_dates"
("date", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING
"id" [["date", "2016-04-01"], ["created_at", "2016-04-01
08:21:44.864669"], ["updated_at", "2016-04-01 08:21:44.864669"]] SQL
(0.4ms) INSERT INTO "referee_stats" ("games_count", "showcase_id",
"game_date_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4,
$5) RETURNING "id" [["games_count", 4], ["showcase_id", 1],
["game_date_id", 7], ["created_at", "2016-04-01 08:21:44.866897"],
["updated_at", "2016-04-01 08:21:44.866897"]] (18.1ms) COMMIT
Redirected to http://localhost:3000/showcases Completed 302 Found in
31ms (ActiveRecord: 20.1ms)
GameDate.find_or_create_by(game_date_params) would find record with ALL game_date_params, so you could do this by finding with specific params like date and assign rest of attributes to it via block. for example:
def create
# find or initialize the record
#game_date = GameDate.find_or_initalize_by(date: game_date_params[:date]) do |game_date|
# Accept nested attributes as well
game_date.assign_attributes(game_date_params)
end
if #game_date.save
redirect_to showcases_path
flash[:success] = "Game date created"
else
render 'new'
end
end
See also: find_or_create_by and AttributesAssignment API docs
It should be like :
def create
#game_date = GameDate.find_or_create_by(game_date_params)
if #game_date.present?
redirect_to showcases_path
flash[:success] = "Game date created"
else
render 'new'
end
end
Create action is for creating an object after the new action has been called and update action if the same but for edit. Mixing create & update logic i not a good idea. Maybe you should rethink what are you trying to do in your views.