I have public_activity working on my rails app for the guidelines model. But there is a problem with deleting a guideline. Updating and creating guidelines are fine.
The error says
ActiveRecord::RecordNotSaved (You cannot call create unless the parent is saved):
app/controllers/guidelines_controller.rb:228:in `destroy'
guidelines_controller.rb
def destroy
#guideline = Guideline.find(params[:id])
#guideline.destroy
#guideline.create_activity :destroy, owner: current_user
respond_to do |format|
format.html { redirect_to guidelines_url }
format.json { head :no_content }
end
end
def update
#guideline = Guideline.find(params[:id])
if #guideline.update_attributes(params[:guideline])
#guideline.create_activity :update, owner: current_user
end
def create
#guideline = current_user.guidelines.new(params[:guideline])
if #guideline.save
#guideline.create_activity :create, owner: current_user
end
guideline.rb
include PublicActivity::Common
view public_activity/guideline/_destroy.html.erb
deleted a guideline
<% if activity.trackable %>
<%= link_to activity.trackable.title, activity.trackable %>
<% else %>
which can no longer be viewed
<% end %>
the rails log says
Processing by GuidelinesController#destroy as HTML
Parameters: {"authenticity_token"=>"SpdYUFk0Bv1KuVg6oEuDUU4MI3eD6C1nV/3bmd5Xhsg=", "id"=>"9-jannit"}
Guideline Load (0.2ms) SELECT "guidelines".* FROM "guidelines" WHERE "guidelines"."id" = ? LIMIT 1 [["id", "9-jannit"]]
(0.1ms) begin transaction
Comment Load (0.3ms) SELECT "comments".* FROM "comments" WHERE "comments"."guideline_id" = 9
SQL (0.7ms) DELETE FROM "guidelines" WHERE "guidelines"."id" = ? [["id", 9]]
SOLR Request (224.9ms) [ path=#<RSolr::Client:0x007f9ebdc5ea50> parameters={data: <?xml version="1.0" encoding="UTF-8"?><delete><id>Guideline 9</id></delete>, headers: {"Content-Type"=>"text/xml"}, method: post, params: {:wt=>:ruby}, query: wt=ruby, path: update, uri: http://localhost:8982/solr/update?wt=ruby, open_timeout: , read_timeout: } ]
(3.3ms) commit transaction
(0.1ms) begin transaction
SOLR Request (4.8ms) [ path=#<RSolr::Client:0x007f9ebdc5ea50> parameters={data: <?xml version="1.0" encoding="UTF-8"?><delete><id>Guideline 9</id></delete>, headers: {"Content-Type"=>"text/xml"}, method: post, params: {:wt=>:ruby}, query: wt=ruby, path: update, uri: http://localhost:8982/solr/update?wt=ruby, open_timeout: , read_timeout: } ]
(0.1ms) commit transaction
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
Completed 422 Unprocessable Entity in 254ms
Perhaps you could try setting :autosave => true in your association. For instance:
class User < ActiveRecord::Base # or wherever location the guidelines association is being set
has_many :guidelines, :autosave => true
...
end
Related
When I submit a form with blank fields that are required I see the ROLLBACK and ActiveModel::Errors in the console but for some reason I can't render the errors in the view.
This is happening on both the new and edit templates.
Needless to say, creating a new record or editing an existing one with the required fields works fine.
This is what my code looks like:
Model: transactions.rb
class Transaction < ApplicationRecord
belongs_to :account
belongs_to :category
validates :date, :description, :amount, :category_id, :account_id, presence: true
end
Controller: transactions_controller.rb
def new
#transaction = Transaction.new
end
def create
#transaction = Transaction.create(transaction_params)
if #transaction.save
redirect_to account_path(#account), notice: "Transaction created"
else
render :new
end
end
def edit
if #transaction.amount > 0
#transaction_type = "income"
else
#transaction_type = "expense"
end
render :edit
end
def update
if #transaction.update(transaction_params)
redirect_to account_path(#account)
else
render :edit
end
end
private
def transaction_params
params.require(:transaction).permit(:date, :description, :amount, :category_id, :account_id)
end
View: new.html.erb (or edit.html.erb)
<ul>
<% #transaction.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
Log after submitting the form:
Started POST "/accounts/15/transactions" for 192.168.55.1 at 2019-09-07 03:00:24 +0000
Cannot render console from 192.168.55.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by TransactionsController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"CJd+/rB6LcUqQAz0ZvY0cf8Dcu+2qzUYLCQHLWE2GElZtJrKbKq2EODFeVvKG6NkE2MxtIIjRreqHAnKu2sJ9A==", "transaction"=>{"date(1i)"=>"2019", "date(2i)"=>"9", "date(3i)"=>"7", "description"=>"", "category_id"=>"1", "amount"=>"0"}, "transaction_type"=>"Expense", "commit"=>"Add Transaction", "account_id"=>"15"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
↳ /var/lib/gems/2.6.0/gems/activerecord-5.2.3/lib/active_record/log_subscriber.rb:98
Account Load (0.1ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT $2 [["id", 15], ["LIMIT", 1]]
↳ app/controllers/transactions_controller.rb:64
(0.1ms) BEGIN
↳ app/controllers/transactions_controller.rb:24
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
↳ app/controllers/transactions_controller.rb:24
(0.2ms) ROLLBACK
↳ app/controllers/transactions_controller.rb:24
(0.1ms) BEGIN
↳ app/controllers/transactions_controller.rb:26
(0.1ms) ROLLBACK
↳ app/controllers/transactions_controller.rb:26
Rendering transactions/new.html.erb within layouts/application
If I add p #transaction.errors in the create method or go into the Rails console and run #transaction.errors I do get the errors:
irb(main):026:0> #transaction.errors
=> #<ActiveModel::Errors:0x0000000006447158 #base=#<Transaction id: nil, date: nil, description: nil, amount: nil, account_id: nil, created_at: nil, updated_at: nil, category_id:
nil>, #messages={:account=>["must exist", "can't be blank"], :category=>["must exist", "can't be blank"], :date=>["can't be blank"], :description=>["can't be blank"], :amount=>["can't be blank"]}, #details={:account=>[{:error=>:blank}, {:error=>:blank}], :category=>[{:error=>:blank}, {:error=>:blank}], :date=>[{:error=>:blank}], :description=>[{:error=>:blank}], :amount=>[{:error=>:blank}]}>
Something else I tried is adding these 2 lines to the new.html.erb:
<%= #transaction.errors %> renders: #<ActiveModel::Errors:0x00007ff650570500>
<%= #transaction.errors.full_messages %> renders: []
Processing by TransactionsController#create as JS, your form is being submitted using ajax, you need to render a js view or use a non-ajax request. Are you using form_with for your form? form_with defaults to remote forms, use form_for instead or update the view using a js response.
I'm using the carrierwave gem to upload images
I have this form in my users view which provides an upload button for a file (image)
<%= form_for(#user, html: { multipart: true }) do |f| %>
Update your profile pic:
<span class="avatar">
<%= f.file_field :avatar %>
</span>
<%= f.submit "Update", class: "btn btn-primary" %>
<% end %>
Here's my users controller
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
end
private
def user_params
params.require(:user).permit(:avatar)
end
end
When I click the submit button on the form from the browser, I get this http request come through.
Started PATCH "/users/1" for 127.0.0.1 at 2018-07-05 13:15:39 +0100
Processing by UsersController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"VXaEvnTD7nl+2d/0n1+iB/zwRX+Mf3nbMt0/Qr7m/nYpTmyXCxih981pIbGKGT9qdSfB7zyB6l
CKGdA9uiLouw==", "user"=>{"avatar"=>#<ActionDispatch::Http::UploadedFile:0x00007fbf2a794af0 #tempfile=#<Tempfile:/var/folders
/42/plkmf9zn755b0lvwc2_5k30c0000gn/T/RackMultipart20180705-37847-7s1tba.png>, #original_filename="Screen Shot 2018-07-03 at 1
0.23.17.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"user[avatar]\"; filename=\"Screen S
hot 2018-07-03 at 10.23.17.png\"\r\nContent-Type: image/png\r\n">}, "commit"=>"Update", "id"=>"1"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], [
"LIMIT", 1]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
No template found for UsersController#update, rendering head :no_content
Completed 204 No Content in 161ms (ActiveRecord: 0.6ms)
But nothing is updated in the database (i.e. the avatar attribute for the current user still has a value of nil). I also can't see that the image has been saved anywhere.
It's your controller update method which is incomplete, for example :
def update
user = User.find(params[:id]) # Set user
if user.update(user_params) # Save to database
# Success, redirect to show/index/whatever
else
# Fail, render form again
end
end
And i recommend you to read this: http://guides.rubyonrails.org/action_controller_overview.html
In my Rails app I have made an api for an iOS app to consume.
I have a user model with a association to a profile:
class User < ActiveRecord::Base
has_one :personal_profile
accepts_nested_attributes_for :personal_profile
end
class PersonalProfile < Profile
belongs_to :user
end
The users_controller.rb looks like this:
class Api::V1::UsersController < Api::V1::ApiController
before_filter :authenticate_api_user, only: [:show, :update]
def create
#user = User.new(user_params)
if #user.save
#user
else
render json: { errors: #user.errors.full_messages }, status: 422
end
end
def show
#user
end
def update
if #user.update(user_params)
#user
else
render json: { errors: #user.errors.full_messages }, status: 422
end
end
private
def user_params
params.require(:user).permit(:name, :email, :birthday, :gender, :password, :password_confirmation, personal_profile_attributes: [:website, :location, :description, :tagline, :tag_tokens, :image, :image_cache])
end
def authenticate_api_user
authenticate_or_request_with_http_token do |token, options|
#user = User.find_by(auth_token: token)
end
end
end
When I do a put request like this:
curl -H 'Authorization: Token token=AUTH_TOKEN' -H 'Content-Type: application/json' -X PUT -d '{"user": {"name": "Frank", "personal_profile_attributes": { "tagline": "New tagline" }}}' http://localhost:3000/api/user
I get this response:
{"errors":["Personal profile title can't be blank."]}
And it's like the server doesn't recognize my params:
Started PUT "/api/user" for ::1 at 2016-01-19 10:16:33 +0100
Processing by Api::V1::UsersController#update as JSON
Parameters: {"user"=>{"name"=>"Frank", "personal_profile_attributes"=>{"tagline"=>"New tagline"}}}
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."auth_token" = $1 LIMIT 1 [["auth_token", AUTH_TOKEN]]
(0.8ms) BEGIN
PersonalProfile Load (1.2ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."type" IN ('PersonalProfile') AND "profiles"."user_id" = $1 ORDER BY title asc LIMIT 1 [["user_id", 1]]
SQL (1.3ms) UPDATE "profiles" SET "user_id" = $1, "updated_at" = $2 WHERE "profiles"."id" = $3 [["user_id", nil], ["updated_at", "2016-01-19 09:16:33.629907"], ["id", 1]]
User Exists (1.3ms) SELECT 1 AS one FROM "users" WHERE (LOWER("users"."email") = LOWER('d#friis.me') AND "users"."id" != 1) LIMIT 1
(0.8ms) ROLLBACK
Completed 422 Unprocessable Entity in 19ms (Views: 0.3ms | ActiveRecord: 6.5ms)
I have another controller setup for the web app, which is pretty standard and works just fine!
Any help is much appreciated!
Okay, so the problem was that I did not pass an ID for the associated record with the request params. This meant that a new associated record was created with the attributes I was trying to update.
Setting the ID solved the problem and updated the record as expected.
{
"user" => {
"personal_profile_attributes" => {
"id" => 1,
"tagline" => "New tagline"
}
}
}
I have made a github repo that you can find here just for this question. I have 3 models:
class User < ActiveRecord::Base
has_many :user_countries
has_many :event_countries,
-> { where(user_countries: {:event => true}) },
:through => :user_countries,
:source => :country
has_many :research_countries,
-> { where(user_countries: {:research => true}) },
:through => :user_countries
:source => :country
end
class UserCountry < ActiveRecord::Base
belongs_to :country
belongs_to :user
end
class Country < ActiveRecord::Base
# ...
end
So a user should be able to choose event_countries and research_countries.
here's my users controller (nothing complicated):
class UsersController < ApplicationController
respond_to :html, :json
before_action :get_user, only: [:show, :edit, :update]
before_action :get_users, only: [:index]
def index
end
def show
end
def edit
end
def update
#user.update_attributes(user_params)
respond_with #user
end
private
def get_user
#user = User.find(params[:id])
end
def get_users
#users = User.all
end
def user_params
params.require(:user).permit(:first_name, :event_countries => [:id, :name])
end
end
And here's my user show page:
<%= best_in_place #user, :first_name %>
<p> event countries: </p>
<%= best_in_place #user, :event_countries, place_holder: "click here to edit", as: :select, collection: Country.all.map {|i| i.name} %>
<%= link_to "users index", users_path %>
So there's really nothing complicated here. I can also succesfully edit my users first name, best_in_place is working fine.
The question is: how do I edit the event_countries ? As you can see I tried to use the collection option with the countries but when I try to select a country I get the following:
Processing by UsersController#update as JSON
Parameters: {"user"=>{"event_countries"=>"3"}, "authenticity_token"=>"l5L5lXFmJFQ9kI/4klMmb5jDhjmtQXwn6amj1uwjSuE=", "id"=>"6"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 6]]
(0.1ms) begin transaction
(0.1ms) rollback transaction
Completed 500 Internal Server Error in 3ms
NoMethodError (undefined method `each' for nil:NilClass):
app/controllers/users_controller.rb:17:in `update'
I don't understand what it's doing, I know it must be a problem with the collection option. If you need to see any file please check my repo here:
https://github.com/spawnge/best_in_place_join_models_twice . I have a spent a lot of time on this any answer/suggestion would be greatly appreciated :)
update:
I have tried this:
<%= best_in_place #user, :event_country_ids, as: :select, collection: Country.all.map { |i| i.name }, place_holder: "click here to edit", html_attrs: { multiple: true } %>
and I have added :event_country_ids to my user params:
params.require(:user).permit(:first_name, :event_country_ids)
And now I can see all the countries but when I select one here's what I get:
Started PUT "/users/3" for 127.0.0.1 at 2014-12-18 01:19:27 +0000
Processing by UsersController#update as JSON
Parameters: {"user"=>{"event_country_ids"=>"1"}, "authenticity_token"=>"aZAFIHgzdSL2tlFcGtyuu+XIJW3HX2fwQGHcB9+iYpI=", "id"=>"3"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 3]]
(0.0ms) begin transaction
Country Load (0.0ms) SELECT "countries".* FROM "countries" WHERE "countries"."id" = ? LIMIT 1 [["id", 1]]
Country Load (0.0ms) SELECT "countries".* FROM "countries" INNER JOIN "user_countries" ON "countries"."id" = "user_countries"."country_id" WHERE "user_countries"."event" = 't' AND "user_countries"."user_id" = ? [["user_id", 3]]
SQL (0.1ms) DELETE FROM "user_countries" WHERE "user_countries"."user_id" = ? AND "user_countries"."country_id" = 2 [["user_id", 3]]
SQL (0.0ms) INSERT INTO "user_countries" ("country_id", "event", "user_id") VALUES (?, ?, ?) [["country_id", 1], ["event", "t"], ["user_id", 3]]
(20.9ms) commit transaction
Completed 204 No Content in 28ms (ActiveRecord: 21.3ms)
As you can see it seems that it insert the right content: INSERT INTO "user_countries" ("country_id", "event", "user_id") VALUES (?, ?, ?) [["country_id", 1], ["event", "t"], ["user_id", 3]] However I get the Completed 204 No Content just after that. I don't understand when I refresh the page the input is empty. Any suggestion ?
Update 2:
I checked in the console and it works, I can add event_countries to a user. However it doesn't display the user's event_countries when I refresh the page, I guess that's because I'm using the event_country_ids object.
I think the following code should work:
<%= best_in_place #user, :event_country_ids, as: :select,
collection: Country.all.each_with_object({}) { |i, memo| memo[i.id] = i.name },
place_holder: "click here to edit",
html_attrs: { multiple: true } %>
Assuming you want the user to be able to assign multiple event_countries.
Reference
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many, specifically the collection_singular_ids= method created by has_many.
https://github.com/bernat/best_in_place#select, the structure of the collection needs to be a hash. For each key => value pair, the key is what's submitted with the form and the value is what's displayed to the user.
http://ruby-doc.org/core-2.1.5/Enumerable.html#method-i-each_with_object, each_with_object is a part of the core Ruby library.
I have Subcategories which belong to Categories. My app saves (build) all my Subcategories under Subcategory with id = 1, even though my code seems to be ok and it is not supposed to do that:
Subcategories controller:
def create
#category = Category.find_by(params[:id])
#subcategory = #category.subcategories.build(subcategory_params)
if #subcategory.save
flash[:success] = "added subcategory"
redirect_to admin_categories_url
else
render :new
end
end
...
private
def subcategory_params
params.require(:subcategory).permit(:name, :category_id)
end
Subcategory.rb
class Subcategory < ActiveRecord::Base
belongs_to :category
has_many :products
validates :name, presence: true
validates :category_id, presence: true
end
Form:
<h3>Add a subcategory</h3>
<%= form_for [#category, #subcategory] do |f| %>
<%= f.text_field :name, placeholder: "Name" %>
<%= f.submit "Add a subcategory" %>
<% end %>
router:
resources :categories do
resources :subcategories
end
URL:
Adding a new subcategory to category with id = 3
http://localhost:3000/categories/3/subcategories/new
Logs:
Started POST "/categories/1/subcategories" for 127.0.0.1 at 2014-04-16 16:04:47 +0400
Processing by SubcategoriesController#create as HTML
Parameters: {"utf8"=>"✓", authenticity_token"=>"74U3VyAN6NqEjhkuHGNHnPda/yzpc+dIcn2xBJ6Zi2A=", "subcategory"=>{"name"=>"A name"}, "commit"=>"Add subcategory", "category_id"=>"1"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT 1 [["id", 1]]
(0.1ms) BEGIN
SQL (0.2ms) INSERT INTO "subcategories" ("category_id", "created_at", "name", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["category_id", 1], ["created_at", "2014-04-16 12:04:47.151729"], ["name", "A name"], ["updated_at", "2014-04-16 12:04:47.151729"]]
(0.8ms) COMMIT
Id is 1
What can be the problem here?
Update
When doing
#category = Category.find_by(params[:category_id])
this error comes up:
ERROR: argument of WHERE must be type boolean, not type integer
LINE 1: SELECT "categories".* FROM "categories" WHERE (1) LIMIT 1
If doing
#category = Category.find(params[:category_id])
problem presists
In your create action you are picking up the id of the subcategory, not the category. Change it to:
def create
#category = Category.find(params[:category_id])
...
The same change to setting #category needs to be made in the new method too so that category_id comes back as 3 in the params from the view. Of course this duplication can be also DRYed up using a helper method in the controller.
To see the difference in the id, you can use rake routes and you should see something like:
new_category_subcategory GET /categories/:category_id/subcategories/new subcategories#new
This shows you that it expects the parameter category_id for the id of the category.
Look at your parameters it consist category_id not id
Parameters: {"utf8"=>"✓", authenticity_token"=>"74U3VyAN6NqEjhkuHGNHnPda/yzpc+dIcn2xBJ6Zi2A=", "subcategory"=>{"name"=>"A name"}, "commit"=>"Add subcategory", "category_id"=>"1"}
#=> "category_id"=>"1"
Category.find_by(category_id: params[:category_id])
So you need to do
def create
#category = Category.find_by(category_id: params[:category_id])
#subcategory = #category.subcategories.build(subcategory_params)
if #subcategory.save
flash[:success] = "added subcategory"
redirect_to admin_categories_url
else
render :new
end
end