I am attempting to use the trix/actiontext feature of rails 7 to upload images to be included in my blog. I am planning to store them in AWS-S3 bucket, but the problem also happens when trying to store on local disk. Trix works normally when just doing text content with no errors. When I click the "paperclip" icon to attach a file, I get prompted to select a file, and it appears that I am able to, however, there are errors in the console and when I click submit, the file does not save.
This is the error in the console as soon as I choose an image to attach:
POST http://localhost:3000/rails/active_storage/direct_uploads 422
(Unprocessable Entity) actiontext.js:543
Uncaught Error: Direct upload failed: Error creating Blob for
"Screenshot from 2022-10-13 12-38-57.png". Status: 422
at AttachmentUpload.directUploadDidComplete (actiontext.js:849:13)
at BlobRecord2.callback (actiontext.js:618:13)
at BlobRecord2.requestDidError (actiontext.js:560:12)
at BlobRecord2.requestDidLoad (actiontext.js:556:14)
at XMLHttpRequest. (actiontext.js:527:56)
Here is the error from the rails server:
Started POST "/rails/active_storage/direct_uploads" for ::1 at
2022-11-03 14:20:10 -0500 14:20:10 web.1 | Processing by
ActiveStorage::DirectUploadsController#create as JSON 14:20:10 web.1
| Parameters: {"blob"=>{"filename"=>"Screenshot from 2022-10-26
15-49-39.png", "content_type"=>"image/png", "byte_size"=>336871,
"checksum"=>"TZneH7Z7DdCSftEvona6zg=="},
"direct_upload"=>{"blob"=>{"filename"=>"Screenshot from 2022-10-26
15-49-39.png", "content_type"=>"image/png", "byte_size"=>336871,
"checksum"=>"TZneH7Z7DdCSftEvona6zg=="}}} 14:20:10 web.1
Completed 422 Unprocessable Entity in 33ms (ActiveRecord: 8.4ms |
Allocations: 14851)
ActiveRecord::RecordInvalid (Validation failed: Service name can't be
blank): 14:20:10
There is of course a much longer stack trace, but that appears to be the important part. I'm happy to provide the rest if anyone wants it.
When I click submit on the form, I get my normal toast message saying blog is successfully updated, but the image file is not added to the post. I've been searching for the answer to this problem for 3 days and I'm starting to go around in circles. I know that service_name is a column in the actives_storage_blobs database table, but I don't know where it pulls service name from or how to get it there. I'm thinking it's from the service in storage.yml, and it is present there.
storage.yml:
local:
service: Disk
root: <%= Rails.root.join("storage") %>
I'm running out of things to try and search for this problem. I have disabled turbo for the blogs page as I had found a github discussion relating to that, but it hasn't helped. I have read through the guides for active storage and action text multiple times and have not found anything that helped. I would greatly appreciate any suggestions. Thank you.
In case it helps:
Here is the relevant part of the form at app/views/blogs/_form.html.erb:
<div class="form-group">
<%= form.rich_text_area :body, class: 'form-control', rows: 15, placeholder: 'Content' %>
</div>
app/controllers/blogs_controller.rb:
class BlogsController < CommentsController
before_action :set_blog, only: %i[ show edit update destroy toggle_status ]
before_action :set_sidebar_topics, except: [:update, :create, :destroy, :toggle_status]
layout "blog"
access all: [:show, :index], user: { except: [:destroy, :new, :create, :update, :edit, :toggle_status] }, admin: :all, testing: { except: [:destroy, :create, :update]}
def index
if logged_in?(:admin) || logged_in?(:testing)
#blogs = Blog.recent.with_rich_text_body_and_embeds.page(params[:page]).per(5)
else
#blogs = Blog.published.recent.with_rich_text_body_and_embeds.page(params[:page]).per(5)
end
#page_title = "My Portfolio Blog"
end
def show
if logged_in?(:admin) || logged_in?(:testing) || #blog.published?
#blog = Blog.includes(:comments).friendly.find(params[:id])
#comment = Comment.new
#page_title = #blog.title
#seo_keywords = #blog.body
else redirect_to blogs_path, notice: 'You are not authorized to access this page.'
end
end
def new
#blog = Blog.new
end
def edit
end
def create
#blog = Blog.new(blog_params)
respond_to do |format|
if #blog.save
format.html { redirect_to blog_url(#blog), success: "Blog was successfully created." }
else
flash[:danger] = "Blog must have title, body and topic."
format.html { render :new, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #blog.update(blog_params)
format.html { redirect_to blog_url(#blog), success: "Blog was successfully updated." }
else
format.html { render :edit, status: :unprocessable_entity }
end
end
end
def destroy
#blog.destroy
respond_to do |format|
format.html { redirect_to blogs_url, status: :see_other }
end
end
def toggle_status
if #blog.draft? && logged_in?(:admin)
#blog.published!
elsif #blog.published? && logged_in?(:admin)
#blog.draft!
end
redirect_to blogs_url, success: 'Post status has been updated.'
end
private
def set_blog
#blog = Blog.friendly.find(params[:id])
end
def blog_params
params.require(:blog).permit(:title, :body, :topic_id, :status, images: [])
end
def set_sidebar_topics
#side_bar_topics = Topic.with_blogs
end
end
app/models/blog.rb:
class Blog < ApplicationRecord
enum status: { draft: 0, published: 1 }
extend FriendlyId
friendly_id :title, use: :slugged
validates_presence_of :title, :body, :topic_id
has_rich_text :body
has_many_attached :images, dependent: :destroy
has_many :comments, as: :commentable, dependent: :destroy, counter_cache: :commentable_count
belongs_to :topic, optional: true
def self.special_blogs
all
end
def self.featured_blogs
limit(2)
end
def self.recent
order("updated_at DESC")
end
end
ActiveRecord::Schema[7.0].define(version: 2022_10_14_225319) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "action_text_rich_texts", force: :cascade do |t|
t.string "name", null: false
t.text "body"
t.string "record_type", null: false
t.bigint "record_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["record_type", "record_id", "name"], name: "index_action_text_rich_texts_uniqueness", unique: true
end
create_table "active_storage_attachments", force: :cascade do |t|
t.string "name", null: false
t.string "record_type", null: false
t.bigint "record_id", null: false
t.bigint "blob_id", null: false
t.datetime "created_at", null: false
t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
end
create_table "active_storage_blobs", force: :cascade do |t|
t.string "key", null: false
t.string "filename", null: false
t.string "content_type"
t.text "metadata"
t.string "service_name", null: false
t.bigint "byte_size", null: false
t.string "checksum"
t.datetime "created_at", null: false
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
end
create_table "active_storage_variant_records", force: :cascade do |t|
t.bigint "blob_id", null: false
t.string "variation_digest", null: false
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
end
create_table "blogs", force: :cascade do |t|
t.string "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.integer "status", default: 0
t.bigint "topic_id"
t.integer "commentable_count"
t.text "body"
t.index ["slug"], name: "index_blogs_on_slug", unique: true
t.index ["topic_id"], name: "index_blogs_on_topic_id"
end
create_table "comments", force: :cascade do |t|
t.bigint "user_id", null: false
t.string "commentable_type", null: false
t.bigint "commentable_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "body"
t.index ["commentable_type", "commentable_id"], name: "index_comments_on_commentable"
t.index ["user_id"], name: "index_comments_on_user_id"
end
create_table "friendly_id_slugs", force: :cascade do |t|
t.string "slug", null: false
t.integer "sluggable_id", null: false
t.string "sluggable_type", limit: 50
t.string "scope"
t.datetime "created_at"
t.index ["slug", "sluggable_type", "scope"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope", unique: true
t.index ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type"
t.index ["sluggable_type", "sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_type_and_sluggable_id"
end
create_table "portfolios", force: :cascade do |t|
t.string "title"
t.string "subtitle"
t.text "body"
t.text "main_image"
t.text "thumb_image"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "position"
end
create_table "skills", force: :cascade do |t|
t.string "title"
t.integer "percent_utilized"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "badge"
end
create_table "technologies", force: :cascade do |t|
t.string "name"
t.bigint "portfolio_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["portfolio_id"], name: "index_technologies_on_portfolio_id"
end
create_table "topics", force: :cascade do |t|
t.string "title"
t.datetime "created_at", null: false
t.datetime "updated_at", 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 "name"
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.string "roles"
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
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
add_foreign_key "blogs", "topics"
add_foreign_key "comments", "users"
add_foreign_key "technologies", "portfolios"
end
I am going to stop this question. It appears that rails needed updating. I did rails app:update and there were updates related to actiontext and activestorage and the DB schema was updated for those 3 relevant tables. I have done an upload through action text and it has worked. It's not displaying properly but there is data in my storage folder. I am going to go through everything as it is now to see if I can get the image to display properly and will ask a new question if needed. Thank you very much for helping.
Edit to add: Updating rails did fix the uploads completely. The update changed the image processor from mini-magick to vips. Adding this line to application.rb switched it back and then everything worked properly.
config.active_storage.variant_processor = :mini_magick
Related
I have used 4 important gems
gem 'activeadmin'
gem 'devise'
gem 'cancancan', '~> 2.0'
gem 'friendly_id', '~> 5.2.4'
I have 2 main Controller "User" and "Post" and registered in active_admin(rails generate active_admin:resource User and rails generate active_admin:resource Post).I have used cancancan for the authorization.
I have defined the ability in
ability.rb
if user.admin?
can :manage, :all
else
can :read, Posts
end
ApplicationController.rb
class ApplicationController < ActionController::Base
protect_from_forgery
rescue_from CanCan::AccessDenied do |exception|
respond_to do |format|
format.json { head :forbidden, content_type: 'text/html' }
format.html { redirect_to main_app.root_url, notice: exception.message }
format.js { head :forbidden, content_type: 'text/html' }
end
end
def current_ability
#current_ability ||= AccountAbility.new(current_admin_user)
end
end
schema.rb
ActiveRecord::Schema.define(version: 2019_02_14_200911) do
create_table "active_admin_comments", force: :cascade do |t|
t.string "namespace"
t.text "body"
t.string "resource_type"
t.integer "resource_id"
t.string "author_type"
t.integer "author_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["author_type", "author_id"], name: "index_active_admin_comments_on_author_type_and_author_id"
t.index ["namespace"], name: "index_active_admin_comments_on_namespace"
t.index ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource_type_and_resource_id"
end
create_table "admin_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", null: false
t.datetime "updated_at", null: false
t.boolean "admin", default: true
t.index ["email"], name: "index_admin_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_admin_users_on_reset_password_token", unique: true
end
create_table "categories", force: :cascade do |t|
t.string "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "published_at"
t.integer "user_id"
t.integer "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.index ["category_id"], name: "index_posts_on_category_id"
t.index ["slug"], name: "index_posts_on_slug", unique: true
t.index ["user_id"], name: "index_posts_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.boolean "admin", default: false
t.index ["slug"], name: "index_users_on_slug", unique: true
end
end
Goal
My goal is: 1. Only Admin can post,add user, add category basically manage all.
2. guest User can only read.
So I used cancancan gem to do authorization. But I am getting error:
uninitialized constant ApplicationController::AccountAbility
Extracted source (around line #12):
end
def current_ability
#current_ability ||= AccountAbility.new(current_admin_user)
end
end
And I have uploaded on git if you need any further information.
It will be great if you can help me. Thanks in advance.
The NameError is because your model is named Ability, not AccountAbility, so change your current_ability method to:
def current_ability
#current_ability ||= Ability.new(current_admin_user)
end
First stack overflow question, so I apologize ahead of time for forgetting things.
Project:
Announcement Feature, which allows admin / moderators to post announcements on website.
Tools/Languages Used:
React / Ruby on Rails, Devise (for login)
History:
The announcement feature was UP and RUNNING; until I added a "Username" field to my Announcement table. I properly updated the migration/schema, and made adjustments to the controller, to permit the new field, as well as the React form, to pass the new field into the announcements object.
Error:
After updating migration/schema files with new fields, updating announcement_controller to permit the new field, and updating the React form to capture and POST the new "Announcement" object through an AXIOS POST request, I get the following error: "Filter chain halted as :authenticate_user! rendered or redirected" 401 unauthorized, etc.
Things I've Tried So Far:
I've verified all the data the SHOULD be in the announcement object, just before being pushed through the POST request, is where it should be. (See images below)
I tried using a Binding.Pry, which works like Javascript's "Debugger" except for Ruby, but my binding.pry wasn't stopping ANYWHERE in the announcements controller, which leads me to believe the POST request isn't even making it to the announcements_controller before the error below.
I've verified the Announcements table is what it should be.
I've set the new field to to be permitted in the announcement_controller
Code Examples / Images:
handleSubmit POST request
handleSubmit = (announcement) => { axios.post(`/api/announcements`, announcement)}
Contents of "announcement" JUST before being passed into handleSubmit()
Filter Chain Halted as :authenticate_user! rendered or redirect: Error Message AFTER POST request
Announcements schema / database / table
ActiveRecord::Schema.define(version: 2018_12_19_224825) do
# These are extensions that must be enabled in order to support this
database
enable_extension "plpgsql"
create_table "accounts", force: :cascade do |t|
t.string "account_name"
t.bigint "users_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["users_id"], name: "index_accounts_on_users_id"
end
create_table "announcements", force: :cascade do |t|
t.string "body"
t.bigint "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_announcements_on_user_id"
end
create_table "games", force: :cascade do |t|
t.string "game_name"
t.bigint "accounts_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["accounts_id"], name: "index_games_on_accounts_id"
end
create_table "team_has_tournaments", force: :cascade do |t|
t.bigint "tournament_id"
t.bigint "team_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["team_id"], name: "index_team_has_tournaments_on_team_id"
t.index ["tournament_id"], name: "index_team_has_tournaments_on_tournament_id"
end
create_table "teams", force: :cascade do |t|
t.string "team_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "tournaments", force: :cascade do |t|
t.text "tournament_description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "tournament_name"
end
create_table "user_has_teams", force: :cascade do |t|
t.bigint "user_id"
t.bigint "team_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["team_id"], name: "index_user_has_teams_on_team_id"
t.index ["user_id"], name: "index_user_has_teams_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "provider", default: "email", null: false
t.string "uid", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.boolean "allow_password_change", default: false
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.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.string "firstName"
t.string "lastName"
t.string "username"
t.string "image"
t.string "email"
t.json "tokens"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "level", default: 1
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
t.index ["uid", "provider"], name: "index_users_on_uid_and_provider", unique: true
end
add_foreign_key "accounts", "users", column: "users_id"
add_foreign_key "announcements", "users"
add_foreign_key "games", "accounts", column: "accounts_id"
add_foreign_key "team_has_tournaments", "teams"
add_foreign_key "team_has_tournaments", "tournaments"
add_foreign_key "user_has_teams", "teams"
add_foreign_key "user_has_teams", "users"
end
Announcements controller that should be handling POST request (1)
Announcements controller that should be handling POST request (2)
class Api::AnnouncementsController < ApplicationController
before_action :set_announcement, only: [:show, :update, :destroy]
def index
render json: Announcement.all.order("created_at DESC")
end
def show
render json: #announcement
end
def new
#announcement = Announcement.new
end
def edit
end
def create
announcement = Announcement.new(announcement_params)
if announcement.save
render json: build_announcement(announcement)
else
render json: announcement.errors, status: 422
end
end
def update
if #announcement.update(announcement_params)
render json: #announcement
else
render json: #announcement.errors, status: 422
end
end
def destroy
#announcement.destroy
end
private
def build_announcement(announcement)
{
id: announcement.id,
body: announcement.body,
username: announcement.username,
user_id: announcement.user_id,
created_at: announcement.created_at,
updated_at: announcement.updated_at,
}
end
def set_announcement
#announcement = Announcement.find(params[:id])
end
def announcement_params
params.require(:announcement).permit(:body, :username, :user_id)
end
end
I note that your console output includes:
User Load (50.0ms) SELECT "users".* FROM "users" WHERE "users"."uid" = $1 LIMIT $2 [["uid", "admin#admin.com"], ["LIMIT", 1]]
(notwithstanding any typing errors on my part.)
It appears that you are trying to find the user with a uid of admin#admin.com. In your comments (deleted now, I think), you had said that you don't have such a user. If that's the case, then I assume that is what's causing your:
Filter chain halted as :authenticate_user! rendered or redirected
I think I would start with researching that bit.
I am struggling to authorize an index for a model that doesn't have a direct relationship with my User model. Actually, I am struggling to wrap my head around the idea of Pundit scopes.
I understand that I can't authorize #sites within my SitePolicy, and from all the reading I have done, I believe I just need to do it in a Scope within the SitePolicy Class, but am unsure how to do this.
Here's what I have:
Models
User
has_one :business
has_many :locations, :through => :business
end
Business
belongs_to :user
has_many :locations
end
Location
extend FriendlyId
belongs_to :business
has_one :user, :through => :business
has_many :sites, dependent: :destroy
friendly_id :custom_url, use: :slugged
end
Site
belongs_to :location
end
routes.rb
resources :locations do
resources :sites
end
sites_controller.rb
class SitesController < ApplicationController
before_action :set_site, only: [:show, :edit, :update, :destroy]
before_action :set_location, only: [:new, :show, :edit, :index, :update, :destroy]
def index
#sites = #location.sites.all
authorize Site
end
private
def set_site
#site = Site.find(params[:id])
end
def set_location
#location = Location.friendly.find(params[:location_id])
end
def site_params
params.require(:site).permit(:location_id, :site, :url, :review_site_id, :number_of_reviews, :average_rating, :extra_data)
end
end
site_policy.rb
class SitePolicy < ApplicationPolicy
class Scope
attr_reader :user, :scope
def initialize(user, scope)
#user = user
#scope = scope
end
def resolve
if user.has_role? :admin
scope.all
else
scope.where(scope.location.user == user)
end
end
end
def index?
return true if user.present? and user.has_role? :admin
end
...
schema.rb
ActiveRecord::Schema.define(version: 2018_05_28_085645) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "businesses", force: :cascade do |t|
t.string "name"
t.text "description"
t.bigint "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "more_than_one_location"
t.boolean "signed_up"
t.string "slug"
t.index ["more_than_one_location"], name: "index_businesses_on_more_than_one_location"
t.index ["user_id"], name: "index_businesses_on_user_id"
end
create_table "friendly_id_slugs", force: :cascade do |t|
t.string "slug", null: false
t.integer "sluggable_id", null: false
t.string "sluggable_type", limit: 50
t.string "scope"
t.datetime "created_at"
t.index ["slug", "sluggable_type", "scope"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope", unique: true
t.index ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type"
t.index ["sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_id"
t.index ["sluggable_type"], name: "index_friendly_id_slugs_on_sluggable_type"
end
create_table "locations", force: :cascade do |t|
t.string "location_name"
t.string "address_line_1"
t.string "address_line_2"
t.string "city"
t.string "region"
t.string "country"
t.string "postal_code"
t.string "website"
t.string "phone_number"
t.string "location_contact_email"
t.bigint "business_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug", null: false
t.string "custom_url", null: false
t.index ["business_id"], name: "index_locations_on_business_id"
t.index ["custom_url"], name: "index_locations_on_custom_url", unique: true
t.index ["slug"], name: "index_locations_on_slug", unique: true
end
create_table "roles", force: :cascade do |t|
t.string "name"
t.string "resource_type"
t.bigint "resource_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id"
t.index ["resource_type", "resource_id"], name: "index_roles_on_resource_type_and_resource_id"
end
create_table "sites", force: :cascade do |t|
t.bigint "location_id"
t.string "site"
t.string "url"
t.string "review_site_id"
t.integer "number_of_reviews"
t.decimal "average_rating"
t.jsonb "extra_data", default: {}, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["extra_data"], name: "index_sites_on_extra_data", using: :gin
t.index ["location_id"], name: "index_sites_on_location_id"
end
create_table "users", force: :cascade do |t|
t.string "name"
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
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
create_table "users_roles", id: false, force: :cascade do |t|
t.bigint "user_id"
t.bigint "role_id"
t.index ["role_id"], name: "index_users_roles_on_role_id"
t.index ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id"
t.index ["user_id"], name: "index_users_roles_on_user_id"
end
add_foreign_key "businesses", "users"
add_foreign_key "locations", "businesses"
add_foreign_key "sites", "locations"
end
To authorize collections of records, you normally do this with a scope rather than authorizing the action itself. In other words, instead of this:
def index
#sites = #location.sites.all
authorize Site
end
You need to do this:
def index
#sites = policy_scope(#location.sites)
end
Since the link between a site and the user goes through several models, you unfortunately need to JOIN all the way back to the user in order to perform this query in SQL:
class SitePolicy < ApplicationPolicy
class Scope < Scope
def resolve
if user.has_role? :admin
scope.all
else
scope.joins(location: :business)
.where(locations: {businesses: {user: user}})
end
end
end
end
Following this design pattern is why Pundit recommends adding the following code to your application:
class ApplicationController < ActionController::Base
include Pundit
after_action :verify_authorized, except: :index
after_action :verify_policy_scoped, only: :index
end
I am setting up an artist community, where peers review a piece submitted. I want the administrator to turn pieces with good reviews into a product with a price, color variants, and other attributes that are not present in the original piece model, and take away attributes like reviews. Once the administrator transforms this into a product, the piece instance is destroyed. I want the administrator to do this through a form.
ActiveRecord::Schema.define(version: 20150715145051) do
create_table "prints", force: :cascade do |t|
t.string "name"
t.text "description"
t.integer "pledge"
t.integer "rating"
t.string "category"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.boolean "in_production"
end
create_table "products", force: :cascade do |t|
t.string "name"
t.string "creator"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
end
create_table "reviews", force: :cascade do |t|
t.integer "rating"
t.text "comment"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "subproducts", force: :cascade do |t|
t.integer "price"
t.integer "quantity"
t.string "size"
t.datetime "created_at", null: false
t.datetime "updated_at", 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.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.string "avatar_file_name"
t.string "avatar_content_type"
t.integer "avatar_file_size"
t.datetime "avatar_updated_at"
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 want to transform a print into a product. Can I have an example of how this can be done through a form? I don't require the whole bulk of the code, just the gist of the idea. Thank you.
This was an unpopular question, but I found out how to do what I wanted some time later. I will post the solution for anyone that would like to do what I wanted to accomplish.
So I wanted to make an instance of prints into a product page. I set up a control method in the print controller that created a new product instance, using the values of #print to set the product attribute values:
def turn_into_product
#product = Product.new(image: #print.image, name: #print.name, \
description: #print.description, user_id: #print.user_id, print_id: #print.id, \
creator: #print.user.username)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
I then made the connection to this method in the route file:
resources :prints do
member do
put 'flag', 'turn_into_product'
end
end
Finally, I used a 'put' call link_to button on the print show page:
<%= link_to "Turn into Product", turn_into_product_print_path(#print), method: :put, class: "btn btn-success" %>
And voila, New product instance with all the attributes, including images included. At the time of the question I did not have a solid grasp of html method calls in link_to or how to use routes for put methods. I also did not know that you could create instance of another class within a foreign controller. Now that I do, the possibilities seem to have multiplied.
recently I make some modification to my app
I use two functions with 1 user data base, I don't know if I make some mistakes routing or migrating something.
My problem is I can't update attributes of a user, when I try to update I get redirect to main page, and when I try to login says that my account don't exist.
Here my schema
ActiveRecord::Schema.define(version: 20150510044605) do
create_table "comments", force: :cascade do |t|
t.integer "link_id"
t.text "body"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "comments", ["link_id"], name: "index_comments_on_link_id"
add_index "comments", ["user_id"], name: "index_comments_on_user_id"
create_table "links", force: :cascade do |t|
t.string "title"
t.string "url"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
end
add_index "links", ["user_id"], name: "index_links_on_user_id"
create_table "pins", force: :cascade do |t|
t.string "title"
t.text "description"
t.integer "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.integer "user_id"
end
add_index "pins", ["user_id"], name: "index_pins_on_user_id"
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"
t.datetime "updated_at"
t.string "name"
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
create_table "votes", force: :cascade do |t|
t.integer "votable_id"
t.string "votable_type"
t.integer "voter_id"
t.string "voter_type"
t.boolean "vote_flag"
t.string "vote_scope"
t.integer "vote_weight"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "votes", ["votable_id", "votable_type", "vote_scope"], name: "index_votes_on_votable_id_and_votable_type_and_vote_scope"
add_index "votes", ["voter_id", "voter_type", "vote_scope"], name: "index_votes_on_voter_id_and_voter_type_and_vote_scope"
end
App Controller
lass ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |params|
params.permit(
:email, :password, :password_confirmation, :name,
:last_name, :profile_name
)
}
devise_parameter_sanitizer.for(:account_update) { |params|
params.permit(
:email, :password, :password_confirmation, :name,
:last_name, :profile_name
)
}
end
end
And routes
Rails.application.routes.draw do
resources :comments
resources :pins
devise_for :users
resources :links do
member do
put "like", to: "links#upvote"
put "dislike", to: "links#downvote"
end
resources :comments
end
resources :pins do
member do
put "like", to: "pins#upvote"
end
end
authenticated :user do
root 'links#index', as: "authenticated_root"
end
root 'pages#home'
end
I'm new in rails, so I don't know how or what to find.