please help solve the problem. i try set the permissions after install 'cancan' and 'cancancan' gems.
schema.rb:
create_table "roles", force: :cascade do |t|
t.string "name"
end
create_table "roles_users", id: false, force: :cascade do |t|
t.integer "role_id"
t.integer "user_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
................................................................
t.datetime "created_at"
t.datetime "updated_at"
end
models:
class User < ActiveRecord::Base
has_and_belongs_to_many :roles
def role?(role)
return !!self.roles.find_by_name(role.to_s.camelize)
end
end
class Role < ActiveRecord::Base
has_and_belongs_to_many :users
end
app/models/ability.rb:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.role? :admin
can :manage, :all
elsif user.role? :manager
can :manage, :review
cannot :manage, :user
elsif user.role? :user
cannot :manage, :all
end
end
end
i filled my roles table follow values:
id name
0 user
1 manager
2 admin
i filled my join table 'roles_users' follow values:
role_id user_id
2 2
1 3
0 1
but after run application permissions is no effect. the problem is that managers can change info for all users. it is not right. please help to fix it
ps:
my user controller:
class UserController < ApplicationController
load_and_authorize_resource
end
after manager change info about user via adminpanel, console output follow:
Started GET "/admin/users/1" for 127.0.0.1 at 2015-09-19 20:53:47 +0300
Processing by Admin::UsersController#show as HTML
Parameters: {"id"=>"1"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 3]]
(0.1ms) SELECT COUNT(*) FROM "active_admin_comments" WHERE "active_admin_comments"."resource_type" = ? AND "active_admin_comments"."resource_id" = ? AND "active_admin_comments"."namespace" = ? [["resource_type", "User"], ["resource_id", "1"], ["namespace", "admin"]]
CACHE (0.0ms) SELECT COUNT(*) FROM "active_admin_comments" WHERE "active_admin_comments"."resource_type" = ? AND "active_admin_comments"."resource_id" = ? AND "active_admin_comments"."namespace" = ? [["resource_type", "User"], ["resource_id", "1"], ["namespace", "admin"]]
Rendered /home/kalinin/.rvm/gems/ruby-2.0.0-p598/bundler/gems/activeadmin-893b46c6530c/app/views/active_admin/resource/show.html.arb (316.7ms)
Completed 200 OK in 321ms (Views: 318.9ms | ActiveRecord: 0.3ms)
You don't need that .camelize call in your role? method, since all your roles in db are stored in lower-case (manager) and not in camelCase (ManagerOfTheApplication).
It seems your Admin::UsersController is located in active_admin. Try to enable active_admin and can_can integration:
config.authorization_adapter = ActiveAdmin::CanCanAdapter
Look into the link above on the details.
Related
I have a really dumb issue, I have two models:
class User < ApplicationRecord
belongs_to :role
end
and
class Role < ApplicationRecord
has_many :user
end
I'm trying to get the user and make a join with the role's table to get the role's name and id, like:
"user" : {
"name": "json",
"role": {"name":"admin", "id":1}
}
however, after using:
User.includes(:role).all
I just get the users with a "role_id" value, I've also tried:
User.joins(:role)
With the same result. I've been looking at the official docs at (https://guides.rubyonrails.org/active_record_querying.html) and it should be pretty straightforward but I don't know what I'm doing wrong. Do I need to add something to my migrations?, At my create_user migration I have:
class CreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users do |t|
t.string :username
t.string :email
t.integer :role_id
end
add_index :users, :email
add_index :users, :username
end
end
and my create_roles migration
class CreateRoles < ActiveRecord::Migration[6.0]
def change
create_table :roles do |t|
t.string :name
end
end
end
all by itself doesn't return such a custom data. You can use as_json for that:
User.all.as_json(only: :name, include: { role: { only: [:name, :id] } }, root: true)
# User Load (0.5ms) SELECT "users".* FROM "users"
# Role Load (0.6ms) SELECT "roles".* FROM "roles" WHERE "roles"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
# => [{"user"=>{"name"=>"json", "role"=>{"id"=>1, "name"=>"admin"}}}]
I have added added base_currency_id & base_currency_id2 with & without foreign-key constraint respectively as below in markets table,
def change
create_table :currencies do |t|
t.string :code
t.timestamps
end
create_table :market2 do |t|
t.string :code
t.integer :base_currency_id
t.integer :base_currency_id2
t.foreign_key :currencies, column: :base_currency_id2
t.integer :quote_currency_id
t.timestamps
end
end
ActiveRecord::Migration.change
Market model have following associations defined,
class Market < ApplicationRecord
belongs_to :base_currency, class_name: 'Currency', foreign_key: :base_currency_id
belongs_to :base_currency2, class_name: 'Currency', foreign_key: :base_currency_id2
end
I am not getting why one of the below association is causing N+1 query even on eager-loading here,
Market.includes(:base_currency).each { |x| puts x.base_currency.code }
# Market Load (0.6ms) SELECT "markets".* FROM "markets"
# Currency Load (0.3ms) SELECT "currencies".* FROM "currencies" WHERE "currencies"."id" = $1 [["id", 1]]
# INR
# INR
Market.includes(:base_currency2).each { |x| puts x.base_currency.code }
# Market Load (0.5ms) SELECT "markets".* FROM "markets"
# Currency Load (0.4ms) SELECT "currencies".* FROM "currencies" WHERE "currencies"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
# INR
# Currency Load (0.4ms) SELECT "currencies".* FROM "currencies" WHERE "currencies"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
# INR
Please explain if I miss something here.
change the association called inside the block to base_currency2 in the latter.
Market.includes(:base_currency2).each { |x| puts x.base_currency2.code }
I have this model:
class Book < ApplicationRecord
has_many :pages, dependent: :destroy
end
And this one:
class Page < ApplicationRecord
belongs_to :book
end
The migration for the Book is:
class CreateBooks < ActiveRecord::Migration[5.0]
def change
create_table :books do |t|
end
end
end
And the migration for Page is:
class CreatePages < ActiveRecord::Migration[5.0]
def change
create_table :pages do |t|
t.references :book, index: true, null: false
end
end
add_foreign_key :pages, :books, on_delete: :cascade
end
Additionally I got some seeds:
Book.create!(
pages: [
Page.new,
Page.new,
Page.new
]
)
rake db:migrate, rake db:seed and all that jazz. I jump into rails c:
Book.first
Book Load (0.1ms) SELECT "books".* FROM "books" ORDER BY "books"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<Book id: 1>
Cool....now?
Page.count
(0.3ms) SELECT COUNT(*) FROM "pages"
=> 3
Makes total sense. Next:
Book.first.destroy
Book Load (0.2ms) SELECT "books".* FROM "books" ORDER BY "books"."id" ASC LIMIT ? [["LIMIT", 1]]
(0.1ms) begin transaction
Page Load (0.1ms) SELECT "pages".* FROM "pages" WHERE "pages"."book_id" = ? [["book_id", 1]]
SQL (0.1ms) DELETE FROM "pages" WHERE "pages"."id" = ? [["id", 1]]
SQL (0.0ms) DELETE FROM "pages" WHERE "pages"."id" = ? [["id", 2]]
SQL (0.0ms) DELETE FROM "pages" WHERE "pages"."id" = ? [["id", 3]]
SQL (0.1ms) DELETE FROM "books" WHERE "books"."id" = ? [["id", 1]]
Yay! Almost there...after seeding again I do this:
Book.first.delete
Book Load (0.1ms) SELECT "books".* FROM "books" ORDER BY "books"."id" ASC LIMIT ? [["LIMIT", 1]]
SQL (144.0ms) DELETE FROM "books" WHERE "books"."id" = ? [["id", 2]]
WTF?
Page.count
(0.1ms) SELECT COUNT(*) FROM "pages"
=> 3
I know delete does not trigger callbacks, so that dependent: :destroy won't help me here. But the foreign key? Hello? I want referential integrity in my database level!! What am I doing wrong? I've tried more things, like moving the on_delete: :cascade to the field definition:
def change
create_table :pages do |t|
t.references :book, index: true, null: false
end
end
But...nope, same result. I've searched and read the ActiveRecord documentation twice, and a few other questions in SO pointed me to my current setup (which is not the project I'm working on, but rather a newly generated one with the same basic configuration to replicate the error - yea, it fails there too), but I just can't put my finger on what's wrong. Perhaps it's just too late and I'm getting too tired. Help? Does Rails even support this? I'm using v5, far, far ahead of 4.2 where the constraints at db level were integrated. My db/schema.rb looks like this:
ActiveRecord::Schema.define(version: 20160218232358) do
create_table "books", force: :cascade do |t|
end
create_table "pages", force: :cascade do |t|
t.integer "book_id", null: false
t.index ["book_id"], name: "index_pages_on_book_id"
end
end
No trace of foreign keys?
For you're testing you are probably using SQLite, here only mysql, mysql2 and postgres are mentioned therefore I think rails does not support foreign keys on SQLite: http://edgeguides.rubyonrails.org/4_2_release_notes.html#foreign-key-support
It is also stated in another so post: https://stackoverflow.com/a/28801481/4560144
please help solve the problem.
table posts
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "body"
end
table tags
create_table "tags", force: :cascade do |t|
t.string "tagname"
end
joined table
create_table "posts_tags", id: false, force: :cascade do |t|
t.integer "post_id"
t.integer "tag_id"
end
model Post
class Post < ActiveRecord::Base
has_and_belongs_to_many :tags
end
model Tag
class Tag < ActiveRecord::Base
has_and_belongs_to_many :posts
end
I need to remove some of the association table posts_tags.
I get from the form set id tags:
[3, 18, 21]
Here is my controller that handles this set id_tags:
def update
if #post.update_attributes(post_params)
#add_new_tags(#post)
p '------------------1'
p params['delete_tags']
p '------------------2'
destroy_tags(params['delete_tags'], #post)
flash[:success] = t :post_updated
redirect_to user_post_path(#user, #post)
else
flash[:error] = t :post_not_updated
render 'edit'
end
end
private
def destroy_tags(tags,post)
tags.each do |tag|
p '=================='
p tag
tag_del = post.tags.find_by_post_id(:post_id => post.id)
if teg_del
post.tags.delete(tag_del)
end
end
end
def post_params
params.require(:post).permit(:delete_tags)
end
as a result, I get the following error message:
undefined method `find_by_post' for #<Tag::ActiveRecord_Associations_CollectionProxy:0x007f097ed78ac8>
the console displays the following message:
Processing by PostsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"jfNoFJVn2dDqIwIdK/SWerFKIPFJ9bTYdWjy4QFBFL8gHrO7TnzhBq4Mcw+uDyDn9atLEAmfcPdlmHBVHMSDHQ==", "post"=>{"title"=>"Corrupti.ggh", "body"=>"Suscipit ut odit labore fugiat quia aliquam."}, "tagnames"=>"", "delete_tags"=>["3", "18", "21"], "commit"=>"Сохранить Post", "locale"=>"ru", "user_id"=>"24", "id"=>"359"}
Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT 1 [["id", 359]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 24]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" = ? LIMIT 1 [["remember_token", "15166203712e74cc4638f34991c141f85c04a0e0"]]
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", "24"]]
(0.1ms) begin transaction
(0.0ms) commit transaction
"------------------1"
["3", "18", "21"]
"------------------2"
"=================="
"3"
Completed 500 Internal Server Error in 6ms (ActiveRecord: 0.5ms)
Since you have a join table, the tags table itself doesn't have a post_id, so that find_by won't work. It isn't needed though because post.tags would retrieve all the tags connected to that post anyway.
You get a lot of the functionality for handling habtm relationships and forms out of the box with rails using things like collection_check_boxes where I don't think you need the extra destroy tags method unless I'm misunderstanding what you are trying to accomplish. You might consider adding/removing tag associations to posts like this:
Post - has_and_belongs_to_many :tags
Tag - has_and_belongs_to_many :posts
Post Update Form:
<legend>Tags</legend>
<div class="form-group">
<%= f.collection_check_boxes(:tag_ids, Tag.all, :id, :name) %>
</div>
Make sure to allow :tag_ids => [] in your controller's post_params
The will allow you to update the tags belonging to the post by adding any new tags that were checked and removing any tags that were unchecked in the form and you can have normal create and update controller actions without need for the extra destroy_tags method.
I'm setting up permissions for each user to determine what access they have to certain data. I have a user model and a permission model that is set up with a has_many and belongs_to association like so:
app/models/permission.rb
class Permission < ActiveRecord::Base
has_many :users
end
app/models/user.rb
class User < ActiveRecord::Base
belongs_to :permission
end
The migration I used to set up this table is as follows:
db/migrate/create_permissions.rb
class CreatePermissions < ActiveRecord::Migration
def change
create_table :permissions do |t|
t.string :group
t.string :can_see
t.string :cant_see
t.timestamps null: false
end
add_column :users, :permissions_id, :integer
end
end
The problem comes when I go into the Rails console. A sample session may look like this:
irb(main):001:0> User.column_names
=> ["id", "name", "email", "created_at", "updated_at", "password_digest", "remember_digest",
"admin", "activation_digest", "activated", "activated_at", "reset_digest", "reset_sent_at",
"last_active_at", "permissions_id"]
irb(main):002:0> User.first.permissions_id
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1
=> 3
irb(main):003:0> User.first.permission
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1
=> nil
irb(main):004:0> Permission.where(id: 3)
Permission Load (0.3ms) SELECT "permissions".* FROM "permissions" WHERE "permissions"."id" =
? [["id", 3]]
=> #<ActiveRecord::Relation [#<Permission id: 3, group: "CA", can_see: "Some stuff", cant_see:
"Some stuff", created_at: "2015-06-22 12:28:55", updated_at: "2015-06-22 12:28:55">]>
irb(main):005:0> User.first.permission.group
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1
NoMethodError: undefined method `group' for nil:NilClass
Commands like User.first.permissions_id return values and that value should be a foreign key for the Permission model, but running User.first.permission returns nil.
Your column should be permission_id, not permissions_id. That is why AR doesn't find the related model.