Table backend translations self-destruct when set to null-sy value - mobility

Not sure if this is a bug, a feature, a missed doc or a bad config, however when I set all of the translation attributes to a null-sy value, then the translation record self-destructs.
I have the table-backend Mobility setup as follows:
schema.rb
create table "base_model", force: :cascade do |t|
t.boolean "is_animal"
t.boolean "is_vehicle"
...
end
create table "base_model_translation", force: :cascade do |t|
t.bigint "base_model_id", null: false
t.string "locale", null: false
t.boolean "is_animal_translation"
t.boolean "is_vehicle_translation"
...
end
base_model.rb
class BaseModel < ApplicationRecord
extend Mobility
has_many :translations,
class_name: "BaseModelTranslations",
autosave: true,
dependent: :destroy
translates :is_animal_translation
translates :is_vehicle_translation
end
base_model_translation.rb
class BaseModelTranslation < ApplicationRecord
belongs_to :base_model,
touch: true,
inverse_of: :translations
end
On the Rails console:
base_model = BaseModel.last
base_model.reload.translations # => []
# SET TO NULLSY
base_model.is_animal_translation = true
base_model.save
base_model.reload.translations
# => [
# <#BaseModel::Translation
# id: 1,
# is_animal_translation: true,
# is_vehicle_translation: nil,
# ...>]
base_model.is_animal_translation = false
base_model.save
base_model.reload.translations # => []
# SET TO PARTIAL NULLSY THEN FULL NULLSY
base_model.is_animal_translation = true
base_model.is_vehicle_translation = true
base_model.save
base_model.reload.translations
# => [
# <#BaseModel::Translation
# id: 1,
# is_animal_translation: true,
# is_vehicle_translation: true,
# ...>]
base_model.is_animal_translation = false
base_model.save
base_model.reload.translations
# => [
# <#BaseModel::Translation
# id: 1,
# is_animal_translation: false,
# is_vehicle_translation: true,
# ...>]
base_model.is_animal_translation = false
base_model.save
base_model.reload.translations # => []
Is this an intended behaviour, if so is there a bypass for this?
EDIT: Looks like this was an an intended behaviour (https://github.com/shioyama/mobility/blob/3cbeaeec8ef0a6d22ee05229141cd2b2bb33b17f/lib/mobility/backends/active_record/table.rb#L306), is there a bypass for this?

Related

Rails add divide calculation to existing query

I have a query in which I pull all users who have invested in the portfolio, like below:
class PortfolioShareholdersQuery
def initialize(portfolio)
#portfolio = portfolio
end
def call
User.joins(:cash_transactions)
.where(cash_transactions: { to_wallet: portfolio.wallet })
.select('users.*, SUM(cash_transactions.shares_number) as total_shares_number')
.group('users.id')
end
attr_reader :portfolio
end
Is it possible to add inside of above query a line that will do the division of two numbers as below?
(user.total_shares_number / portfolio.portfolio_setup_infos.last.total_shares_sold)
# total_shares_number comes from first select
# portfolio_setup_infos is a has_many relation to portfolio
[Edit]
#models association
class User < ApplicationRecord
has_one :wallet, as: :walletable
has_many :cash_transactions, through: :wallet
end
class Portfolio < ApplicationRecord
has_one :wallet, as: :walletable
end
class Wallet < ApplicationRecord
belongs_to :walletable, polymorphic: true
has_many :cash_transactions
end
class CashTransaction < ApplicationRecord
belongs_to :wallet
belongs_to :to_wallet, class_name: 'Wallet', optional: true
end
[Edit 2]
> divisor = portfolio.portfolio_setup_infos.last.total_shares_sold
PortfolioSetupInfo Load (0.5ms) SELECT "portfolio_setup_infos".* FROM "portfolio_setup_infos" WHERE "portfolio_setup_infos"."portfolio_id" = $1 ORDER BY "portfolio_setup_infos"."id" DESC LIMIT $2 [["portfolio_id", 6], ["LIMIT", 1]]
=> 263
> shareholders = User.joins(:cash_transactions).where(cash_transactions: { to_wallet: portfolio.wallet }).select("users.*, SUM(cash_transactions.shares_number) as total_shares_number, (total_shares_number/#{divisor}").group('users.id')
Wallet Load (0.6ms) SELECT "wallets".* FROM "wallets" INNER JOIN "spv_setups" ON "wallets"."walletable_id" = "spv_setups"."id" WHERE "spv_setups"."portfolio_id" = $1 AND "wallets"."walletable_type" = $2 LIMIT $3 [["portfolio_id", 6], ["walletable_type", "SpvSetup"], ["LIMIT", 1]]
User Load (3.3ms) SELECT users.*, SUM(cash_transactions.shares_number) as total_shares_number, (total_shares_number/263 FROM "users" INNER JOIN "wallets" ON "wallets"."walletable_type" = $1 AND "wallets"."walletable_id" = "users"."id" INNER JOIN "cash_transactions" ON "cash_transactions"."wallet_id" = "wallets"."id" WHERE "cash_transactions"."to_wallet_id" = $2 GROUP BY "users"."id" /* loading for inspect */ LIMIT $3 [["walletable_type", "User"], ["to_wallet_id", 8], ["LIMIT", 11]]
Traceback (most recent call last):
ActiveRecord::StatementInvalid (PG::SyntaxError: ERROR: syntax error at or near "FROM")
LINE 1: ... as total_shares_number, (total_shares_number/263 FROM "user...
^
class Portfolio < ApplicationRecord
def divisor
portfolio_setup_infos.last.total_shares_sold
end
end
class PortfolioShareholdersQuery
def initialize(portfolio)
#portfolio = portfolio
#divisor = portfolio.divisor.to_f
end
def call
select =<<-SEL.squish
users.*,
SUM(cash_transactions.shares_number) as total_shares_number,
(SUM(cash_transactions.shares_number)/#{divisor}) as ratio
SEL
User.joins(:cash_transactions)
.where(cash_transactions: { to_wallet: portfolio.wallet })
.select(select)
.group('users.id')
end
attr_reader :portfolio, :divisor
end

TypeError (can't cast File): Rails Carrierwave File upload

I am using Carrierwave and Rails getting the following error while uploading a file.
Started POST "/upload_client_input_file?project_id=7" for 192.168.1.101 at 2018-08-06 10:46:43 +0530
Processing by InputFilesController#upload_client_input_file as /
Parameters: {"file"=>#, #original_filename="input.csv.part_1.1", #content_type="application/octet-stream", #headers="Content-Disposition: form-data; name=\"file\"; filename=\"input.csv.part_1.1\"\r\nContent-Type: application/octet-stream\r\n">, "project_id"=>"7"}
Completed 500 Internal Server Error in 27ms (ActiveRecord: 7.9ms)
TypeError (can't cast File):
app/controllers/input_files_controller.rb:61:in `upload_client_input_file'
My model code:
class InputFile < ApplicationRecord
belongs_to :project
mount_uploader :file, AvatarUploader
end
My uploader code:
class AvatarUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
# include CarrierWave::MiniMagick
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Provide a default URL as a default if there hasn't been a file uploaded:
# def default_url(*args)
# # For Rails 3.1+ asset pipeline compatibility:
# # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
#
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
# end
# Process files as they are uploaded:
# process scale: [200, 300]
#
# def scale(width, height)
# # do something
# end
# Create different versions of your uploaded files:
# version :thumb do
# process resize_to_fit: [50, 50]
# end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
# def extension_whitelist
# %w(jpg jpeg gif png)
# end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
end
My Controller code:
def upload_client_input_file
params.permit!
project_id = params["project_id"]
tempfile = params["file"].tempfile
file = CSV.read(tempfile)
input_file_id = InputFile.find_or_create_by(batch_name: "Test", flag: true, project_id: project_id, file: File.open(tempfile,"r")).id
end

Invalid configured shell error when running the official FreeBSD vagrant box

I tried to run the official FreeBSD vagrant box by using:
vagrant init freebsd/FreeBSD-10.2-STABLE
And afterwards, modified my Vagrantfile accordingly based on the instructions at https://forums.freebsd.org/threads/52717/ by adding the following lines:
Vagrant.configure("2") do |config|
config.vm.guest = :freebsd
config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", disabled: true
config.vm.box = "freebsd/FreeBSD-10.2-STABLE"
config.ssh.shell = "sh"
config.vm.base_mac = "080027D14C66"
config.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--memory", "1024"]
vb.customize ["modifyvm", :id, "--cpus", "1"]
vb.customize ["modifyvm", :id, "--hwvirtex", "on"]
vb.customize ["modifyvm", :id, "--audio", "none"]
vb.customize ["modifyvm", :id, "--nictype1", "virtio"]
vb.customize ["modifyvm", :id, "--nictype2", "virtio"]
end
end
When I issue the vagrant up command:
vagrant up --provider virtualbox
the following error was shown:
The configured shell (config.ssh.shell) is invalid and unable to
properly execute commands. The most common cause for this is using a
shell that is unavailable on the system. Please verify you're using
the full path to the shell and that the shell is executable by the SSH
user.
Regardless of the error, I'm still able to vagrant ssh into the box. However, I'm not able to gracefully shutdown the machine using vagrant halt. It would show the same error as above and does not shutdown at all.
The fix was simple as it was a totally noob mistake on my part. In the Vagrantfile, you should remove all the parts generated when running vagrant init command except for the two lines at the very top. Then paste the suggested ones below those two lines. The complete Vagrantfile should be like the following:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.guest = :freebsd
config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", disabled: true
config.vm.box = "freebsd/FreeBSD-10.2-STABLE"
config.ssh.shell = "sh"
config.vm.base_mac = "080027D14C66"
config.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--memory", "1024"]
vb.customize ["modifyvm", :id, "--cpus", "1"]
vb.customize ["modifyvm", :id, "--hwvirtex", "on"]
vb.customize ["modifyvm", :id, "--audio", "none"]
vb.customize ["modifyvm", :id, "--nictype1", "virtio"]
vb.customize ["modifyvm", :id, "--nictype2", "virtio"]
end
config.vm.network "private_network", ip: "192.168.33.10"
end
What I did wrong was nesting this Vagrant.configure("2") do |config| block inside the auto-generated one.

Update Attributes For Nested Forms

Hello I'm creating an online retail store.
I have a Category model and a Sizes model. They are nested in a form. When I create a Category I also create sizes for that category.
Right now I can create a Category and sizes. However I can't update the sizes in the nested form.
So click edit category and change the name of one size then click update. I get the below error. On screen it just says "has already been taken".
How do I update sizes through this nested form?
/Users/Documents/Safsy/Website/Safsy/Safsy/app/controllers/categories_controller.rb # line 40 CategoriesController#update:
39: def update
=> 40: binding.pry
41: if #category.update(category_params)
42: redirect_to #category
43: flash[:success] = 'Category was successfully updated.'
44: else
45: render "edit"
46: end
47: end
[1] pry(#<CategoriesController>)>
Unpermitted parameters: _destroy, id
Unpermitted parameters: _destroy, id
Unpermitted parameters: _destroy, id
Unpermitted parameters: _destroy, id
Unpermitted parameters: _destroy, id
Unpermitted parameters: _destroy, id
Unpermitted parameters: _destroy, id
Unpermitted parameter: _destroy
Unpermitted parameter: _destroy
Unpermitted parameter: _destroy
Unpermitted parameter: _destroy
Unpermitted parameter: _destroy
Unpermitted parameter: _destroy
Unpermitted parameter: _destroy
(0.1ms) begin transaction
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = ? LIMIT 1 [["id", 64]]
Size Exists (0.1ms) SELECT 1 AS one FROM "sizes" WHERE "sizes"."title" = 'XSmall' LIMIT 1
Size Exists (0.1ms) SELECT 1 AS one FROM "sizes" WHERE "sizes"."title" = 'Small' LIMIT 1
Size Exists (0.1ms) SELECT 1 AS one FROM "sizes" WHERE "sizes"."title" = 'Medium' LIMIT 1
Size Exists (0.1ms) SELECT 1 AS one FROM "sizes" WHERE "sizes"."title" = 'Large' LIMIT 1
Size Exists (0.1ms) SELECT 1 AS one FROM "sizes" WHERE "sizes"."title" = 'XL' LIMIT 1
Size Exists (0.1ms) SELECT 1 AS one FROM "sizes" WHERE "sizes"."title" = 'XXL' LIMIT 1
Size Exists (0.1ms) SELECT 1 AS one FROM "sizes" WHERE "sizes"."title" = 'XXXL' LIMIT 1
CACHE (0.0ms) SELECT 1 AS one FROM "sizes" WHERE "sizes"."title" = 'XSmall' LIMIT 1
CACHE (0.0ms) SELECT 1 AS one FROM "sizes" WHERE "sizes"."title" = 'Small' LIMIT 1
CACHE (0.0ms) SELECT 1 AS one FROM "sizes" WHERE "sizes"."title" = 'Medium' LIMIT 1
CACHE (0.0ms) SELECT 1 AS one FROM "sizes" WHERE "sizes"."title" = 'Large' LIMIT 1
CACHE (0.0ms) SELECT 1 AS one FROM "sizes" WHERE "sizes"."title" = 'XL' LIMIT 1
CACHE (0.0ms) SELECT 1 AS one FROM "sizes" WHERE "sizes"."title" = 'XXL' LIMIT 1
Size Exists (0.1ms) SELECT 1 AS one FROM "sizes" WHERE "sizes"."title" = 'XXXL test' LIMIT 1
Category Exists (0.1ms) SELECT 1 AS one FROM "categories" WHERE ("categories"."name" = 'Shorts' AND "categories"."id" != 68) LIMIT 1
(0.1ms) rollback transaction
Category Model:
class Category < ActiveRecord::Base
has_ancestry
has_many :products
has_many :sizes
validates :name, presence: true, length: { maximum: 20 }, uniqueness: true
accepts_nested_attributes_for :sizes, allow_destroy: true
end
Sizes Model:
class Size < ActiveRecord::Base
validates :title, presence: true, length: { maximum: 15 }
validates :title, uniqueness: true
belongs_to :category
end
Category controller:
class CategoriesController < ApplicationController
before_action :set_category, only: [:show, :edit, :update]
before_action :admin_user, only: [:destroy, :index, :edit, :show]
def index
#categories = Category.all
end
def show
#tags = Product.where(category_id: #category.id).tag_counts_on(:tags)
if params[:tag]
#products = Product.tagged_with(params[:tag])
else
#products = Product.where(category_id: #category.id).order("created_at DESC")
end
end
def new
#category = Category.new
3.times do
#category.sizes.build
end
end
def edit
end
def create
#category = Category.new(category_params)
if #category.save
redirect_to #category
flash[:success] = "You have created a new category"
else
flash[:danger] = "Your category didn't save"
render "new"
end
end
def update
binding.pry
if #category.update(category_params)
redirect_to #category
flash[:success] = 'Category was successfully updated.'
else
render "edit"
end
end
def destroy
category = Category.find(params[:id])
category.sizes.destroy_all
category.destroy
flash[:success] = "Category deleted"
redirect_to categories_path
end
private
def set_category
#category = Category.find(params[:id])
end
def category_params
params.require(:category).permit(:name, :parent_id, size_ids: [], sizes_attributes: [:title])
end
end
Sizes Controller:
class SizesController < ApplicationController
before_action :logged_in_user, only: [:create, :index, :destroy, :update]
before_action :admin_user, only: [:create, :index, :destroy, :update]
def create
#size = Size.create(size_params)
end
def index
#sizes = Size.all
end
def destroy
Size.find(params[:id]).destroy
end
def update
#size.update_attributes(size_params)
end
private
def size_params
params.require(:size).permit(:title, :category_id)
end
end
Here are the params at Category Update method:
39: def update
=> 40: binding.pry
41: if #category.update(category_params)
42: redirect_to #category
43: flash[:success] = 'Category was successfully updated.'
44: else
45: render "edit"
46: end
47: end
[1] pry(#<CategoriesController>)> params
=> {"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"ZHuWURBwIctFJLgZ1HGNeKvGpK8LlgH9S6Mrh7No/CFdjtwNFoNtfi9NIVHBVhApYH/U5tuOzV0eqhSq/95SCw==",
"category"=>
{"name"=>"Shorts",
"parent_id"=>"64",
"sizes_attributes"=>
{"0"=>{"title"=>"XSmall", "_destroy"=>"false", "id"=>"21"},
"1"=>{"title"=>"Small", "_destroy"=>"false", "id"=>"22"},
"2"=>{"title"=>"Medium", "_destroy"=>"false", "id"=>"23"},
"3"=>{"title"=>"Large", "_destroy"=>"false", "id"=>"24"},
"4"=>{"title"=>"XL", "_destroy"=>"false", "id"=>"25"},
"5"=>{"title"=>"XXL", "_destroy"=>"false", "id"=>"26"},
"6"=>{"title"=>"XXXL test", "_destroy"=>"false", "id"=>"27"}}},
"commit"=>"Update Category",
"controller"=>"categories",
"action"=>"update",
"id"=>"68"}
Permit _destroy and id of nested form like this:-
def category_params
params.require(:category).permit(:name, :parent_id, size_ids: [], sizes_attributes: [:id, :title, :_destroy])
end

Carrierwave: how to crop and resize so that the final picture has exactly the same width and height?

I'm using Rails 3 with carrierwave and Rmagick.
I want the picture to be resized exactly to 192 x 135
This seamed simple at first but nothing I tried worked until now.
Anyone found a solution for this? Here is my code for the uploader.
class AvatarUploader < CarrierWave::Uploader::Base
#Include RMagick or MiniMagick support:
include CarrierWave::RMagick
include CarrierWave::MiniMagick
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Provide a default URL as a default if there hasn't been a file uploaded:
def default_url
# # For Rails 3.1+ asset pipeline compatibility:
ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
#
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
end
process :resize_to_fit => [250, 250]
# Process files as they are uploaded:
# process :scale => [200, 300]
#
# def scale(width, height)
# # do something
# end
# Create different versions of your uploaded files:
version :thumb do
process :resize_to_fit => [200, 200]
end
version :medium do
process :resize_to_fit => [250, 250]
end
version :mini do
process :resize_to_fit => [100, nil]
process crop: '100x100+0+0'
end
version :grid do
process :resize_to_fit => [192, 135]
process crop: '192x135+0+0'
end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
# def extension_white_list
# %w(jpg jpeg gif png)
# end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
private
# Simplest way
def crop(geometry)
manipulate! do |img|
img.crop(geometry)
img
end
end
# Resize and crop square from Center
def resize_and_crop(size)
manipulate! do |image|
if image[:width] < image[:height]
remove = ((image[:height] - image[:width])/2).round
image.shave("0x#{remove}")
elsif image[:width] > image[:height]
remove = ((image[:width] - image[:height])/2).round
image.shave("#{remove}x0")
end
image.resize("#{size}x#{size}")
image
end
end
end
Change your line
process :resize_to_fit => [250, 250]
To
process :resize_to_fill => [192, 135]
I asked a similar question about a month ago. Hope this helps! :)