I have a embedded model, Document in the embedded model can only be created by the admin, but users can select in form the value that they want
class User
include Mongoid::Document
embeds_one :state_model, class_name: "state_model", cascade_callbacks: true
accepts_nested_attributes_for :state_model
attr_accessor :current_password, :job_title_str, :state_model_id
convert_id_to_object :state_model_id, :state_model
end
class UsersController << ApplicationController
def update_params
params.require(:user).permit(:state_model_id)
end
end
module ConvertIdToObject
extend ActiveSupport::Concern
module ClassMethods
def convert_id_to_object(id, object)
id, object = id, object
if StateModel.by_id(id).present?
object = StateModel.by_id(id)
else
end
end
end
end
class StateModel
include Mongoid::Document
field :name, type: String, localize: true
field :value, type: String
scope :by_value, -> (value){ where({:value => value}) unless value == ''}
scope :by_id, -> (id){ where({:id => id}) unless id == ''}
embedded_in :user
validates :name, presence: true, uniqueness: true
validates :value, presence: true, uniqueness: true
end
= simple_form_for user do |f|
= f.input :state_model_id , collection: state_collection
= f.button :submit
Post:
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"3/pmSUHrKRx56ycbraKYL+mEuAiS9QlwWt/bTglgsio=",
"user"=>{"state_model_id"=>"5612cb074d6f722582050000"},
"commit"=>"Update User",
"id"=>"bowtch"}
End I have a Notimplemented error raised by my usercontroller Like if don't accept state_model_id as a param ... I'm stuck here ...
Related
I have one table for Products and the product can either be in the interior or exterior or both. So I created another table to save the Products location. Now when admin adds the product I have provided the option to select the location(s) the product can be in, but when it is posted the code says the field can't be blank because of the validation. I am not sure what I am missing or the approach is wrong.
The product model:
class Product < ApplicationRecord
validates :name, presence: true
has_many :product_locations
accepts_nested_attributes_for :product_locations
end
The product location model:
class ProductLocation < ApplicationRecord
enum locations: [:exterior, :interior]
validates :location, presence: true
validates :product_id, presence: true
belongs_to :product
end
The ActiveAdmin file for Product:
ActiveAdmin.register Product do
permit_params :name, product_locations_attributes: {}
actions :all, except: [:show, :destroy]
filter :name
index do
column 'Product Name', :name
actions
end
form do |f|
f.semantic_errors *f.object.errors.keys
f.inputs "Products" do
f.input :name
end
f.has_many :product_locations do |location|
location.inputs "Locations" do
location.input :location, as: :select, multiple: true, collection: ProductLocation.locations.keys
end
end
f.actions
end
controller do
def scoped_collection
Product.where(user_id: nil)
end
end
end
I get a multi-select for the locations which has "Interior" and "Exterior" for selection, but it says the field can't be blank when I select the location and submit the form
The error on save click I get is:
Location can't be blank
The params that get posted are:
Parameters: {"utf8"=>"✓", "product"=>{"name"=>"Test Product", "product_locations_attributes"=>{"0"=>{"location"=>["0", "1"]}}}, "commit"=>"Create Product"}
First, the permit attributes should be,
product_locations_attributes: [:id, :location]
Then, in your form
location.input :location, as: :select, multiple: true, collection: ProductLocation.locations.keys
Since ProductLocation.locations is an array, array.keys is an invalid method.
So, use directly
location.input :location, as: :select, multiple: true, collection: ProductLocation.locations.map { |n| [n,n] }
To store an array of multiple values take serialize field as an array,
class ProductLocation < ApplicationRecord
enum locations: [:exterior, :interior]
serialize :location, Array
validates :location, presence: true
validates :product_id, presence: true
belongs_to :product
end
Note: Inorder to get the serialize work, you need to have the dataType of the location as a text. If it is not text run a migration to change to text data type
Reason for text field: Rails will convert all those object into plain text when storing in database
I have a study that can have participants. I have a simple_form where the user can add participants. It looks a bit like a table:
name | company | email OR mobile | timezone
name | company | email OR mobile | timezone
name | company | email OR mobile | timezone
By default, the screen has three fieldset rows, and the user can add more rows if needed. Each row is one participant.
I would like my participant model to validate only the rows that have been filled out, and ignore rows that are blank because even though we are showing three by default to the user, not all three are required fields.
Here's the relevant portion of app/models/participants.rb.
class Participant < ApplicationRecord
belongs_to :study
validates :name, presence: true
validates :company, presence: true
validates :time_zone, presence: true
if :channel == 'sms'
validates :mobile_number, presence: true
elsif :channel == 'email'
validates :email, presence: true
end
end
In participants_controller.rb I have:
def index
3.times { #study.participants.build } if #study.participants.length.zero?
end
The problem is that I get an error because simple_form thinks that all three fields are required, and not just the first row.
Rails' validators accept conditions:
validates :mobile_number, presence: true, if: Proc.new { |p| p.study.channel == 'sms' }
validates :email, presence: true, if: Proc.new { |p| p.study.channel == 'email' }
By default all inputs are required. When the form object includes
ActiveModel::Validations (which, for example, happens with Active
Record models), fields are required only when there is presence
validation. Otherwise, Simple Form will mark fields as optional. For
performance reasons, this detection is skipped on validations that
make use of conditional options, such as :if and :unless.
And of course, the required property of any input can be overwritten
as needed:
<%= simple_form_for #user do |f| %>
<%= f.input :name, required: false %>
<%= f.input :username %>
<%= f.input :password %>
<%= f.button :submit %>
<% end %>
Try to put all the inputs as required: false. That should allow skip simple_form validations and the data came into the controller and the model can be filtered or/and validated and every other things you want to do before persist.
In the model class you can use several ways of validations for example:
you also can use the :if and :unless options with a symbol corresponding to the name of a method that will get called right before validation happens. This is the most commonly used option.
for example
class Participant < ApplicationRecord
belongs_to :study
validates :name, presence: true
validates :company, presence: true
validates :time_zone, presence: true
validates :mobile_number, presence: true if: :channel_is_sms?
validates :email, presence: true if: :channel_is_email?
def channel_is_sms?
channel == "sms"
end
def channel_is_email?
channel == "email"
end
end
or also you can use custom validator where you do all that you need validate. for example
class MyValidator < ActiveModel::Validator
def validate(record)
unless record.channel == 'sms'
...
... actions here
...
end
end
end
class Person
include ActiveModel::Validations
validates_with MyValidator
end
I'm trying to configure the nested model's fields in :has_many association, but nothing's happening. I'm on Rails 4.2.3, mongoid 4.0.2, rails_admin 0.6.8.
Property has many Characteristics, Product has and belongs to many Characteristics:
/app/models/property.rb
class Property
include Mongoid::Document
include Mongoid::Timestamps
field :handle
field :title, localize: true
has_many :characteristics, inverse_of: :property
accepts_nested_attributes_for :characteristics, allow_destroy: true
validates :handle, presence: true
validates :title, presence: true
end
/app/models/characteristic.rb
class Characteristic
include Mongoid::Document
include Mongoid::Timestamps
field :handle
field :title, localize: true
belongs_to :property, inverse_of: :characteristics
has_and_belongs_to_many :products
validates :property, presence: true
validates :handle, presence: true
validates :title, presence: true
end
/app/models/product.rb
class Product
include Mongoid::Document
include Mongoid::Timestamps
field :handle
field :title, localize: true
field :page_title, localize: true
field :description, localize: true
field :short_description, localize: true
field :meta_description, localize: true
field :meta_keywords, localize: true
has_and_belongs_to_many :characteristics
validates :handle, presence: true
validates :title, presence: true
end
/config/initializers/rails_admin.rb
require 'i18n'
I18n.available_locales = [:ru, :en]
I18n.default_locale = :ru
RailsAdmin.config do |config|
config.main_app_name = Proc.new { |controller| [ "Babylon", "BackOffice - #{controller.params[:action].try(:titleize)}" ] }
config.actions do
dashboard
index
nestable
new
export
bulk_delete
# show
edit
delete
show_in_app
## With an audit adapter, you can add:
# history_index
# history_show
end
config.model Characteristic do
visible false
label I18n.t(:characteristic).capitalize
label_plural I18n.t(:characteristics).capitalize
object_label_method do
:i18n_characteristic
end
create do
field :title do
label I18n.t(:title)
end
end
update do
field :title do
label I18n.t(:title)
end
end
end
config.model Property do
visible true
label I18n.t(:property).capitalize
label_plural I18n.t(:properties).capitalize
object_label_method do
:i18n_property
end
list do
field :title do
label I18n.t(:title).capitalize
formatted_value do
bindings[:view].link_to value[I18n.locale], bindings[:view].rails_admin.edit_path(model_name: 'property', id: bindings[:object]._id.to_s)
end
end
field :handle do
label I18n.t(:handle).capitalize
end
end
create do
field :title do
label I18n.t(:title)
end
group I18n.t(:seo).upcase! do
field :handle do
label I18n.t(:handle)
end
end
group I18n.t(:characteristics).capitalize do
field :characteristics do
label I18n.t(:characteristics)
associated_model_config do
field :title do
label I18n.t(:title).capitalize
end
end
end
end
end
update do
field :title do
label I18n.t(:title)
end
group I18n.t(:seo).upcase! do
field :handle do
label I18n.t(:handle)
end
end
group I18n.t(:characteristics).capitalize do
field :characteristics do
label I18n.t(:characteristics)
associated_model_config do
field :title do
label I18n.t(:title).capitalize
end
end
end
end
end
end
...
end
def i18n_property
title_translations[I18n.locale]
end
def i18n_characteristic
title_translations[I18n.locale]
end
So as you see, I tried to configure fields of Characteristic model in 2 places to show only :title field, but it still shows automatically all it can grab from the model, and doesn't even translate:
Please help find a solution to display nested fields right! Thank you.
Ok, it's all because of the wrong order. To make all work properly, the order should be Property first, and only then Characteristic. I wish it was mentioned in official readme.
I am new to Ruby and Rails. I'm try to create a "Team" object that has a leader id and an array of users attached.
Problems
I am unable to attach the array of users to the team object
I am unable to define leader object, only store its id
Any help greatly appreciated
My Rails Models:
class Team
include Mongoid::Document
include Mongoid::Timestamps::Created
include Mongoid::Timestamps::Created
field :name
field :slug
field :description
field :leader
field :users, type: Array
field :holiday_days_per_year, type: Integer
field :hours_per_day, type: Integer
field :organisation_id, type: Integer
embeds_many :users
validates :name, :holiday_days_per_year, :presence => true
validates :holiday_days_per_year, :hours_per_day, :numericality => true
before_save :set_slug
def set_slug
self.slug = "#{name.parameterize}"
end
end
class User
include Mongoid::Document
include Mongoid::Timestamps::Created
include Mongoid::Timestamps::Created
field :slug
field :first_name
field :last_name
field :birth_date, type: Date
field :job_title
field :job_start_date, type: Date
field :job_probation_ends, type: Date
field :work_email
field :work_address
field :work_phone_number
field :personal_email
field :personal_address
field :personal_phone_number
field :organisation_id, type: Integer
# emails should be unique
validates_uniqueness_of :work_email, :personal_email
validates :first_name, :last_name, :birth_date,
:job_title, :job_start_date, :job_probation_ends,
:work_address, :work_phone_number,
:personal_address, :personal_phone_number,
:presence => true
# validates emails
validates_format_of :work_email, :personal_email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
belongs_to :team, :inverse_of => :users
before_save :set_slug
def set_slug
self.slug = "#{first_name.parameterize}-#{last_name.parameterize}"
end
end
controller action
# POST /teams
# POST /teams.json
def create
new_params = params.permit(
:name, :holiday_days_per_year, :hours_per_day, :leader, :users)
#team = Team.new(new_params)
if #team.save
render json: #team, status: :created, location: #team
else
render json: #team.errors, status: :unprocessable_entity
end
end
JSON Sent
{
holiday_days_per_year: 20
hours_per_day: 8
leader: "522cf27114bc38307a000004"
name: "Tester"
users: [
0: "522cf27114bc38307a000004"
1: "522d966214bc38659300000d"
2: "522dd21214bc38ac6b000011"
]
}
The object is created, but users and leader dont get saved, the object comes back as
{
_id: "522df8c714bc38ef3e000022",
created_at: "2013-09-09T16:35:19.405Z",
description: null,
holiday_days_per_year: 20,
hours_per_day: 8,
leader: "522d966214bc38659300000d",
name: "Tester",
organisation_id: null,
slug: "tester",
users: [ ]
}
In your model, redefine your "as_json" method with the following
class Team < ActiveRecord::Base
..
has_many :users
def as_json(options)
{ :name=>self.name, :leader=>self.leader, :users=>self.users }
end
end
In my controller, I've got error when create action and try create model [can't mass-assignment], but
in my spec, my test of mass-assignment model its pass!?!
My Model:
class Customer < ActiveRecord::Base
attr_accessible :doc, :doc_rg, :name, :birthday, :name_sec, :address, :state_id, :city_id, :district_id,
:customer_pj, :is_customer, :segment_id, :activity_id, :person_type, :person_id
belongs_to :person , :polymorphic => true, dependent: :destroy
has_many :histories
has_many :emails
def self.search(search)
if search
conditions = []
conditions << ['name LIKE ?', "%#{search}%"]
find(:all, :conditions => conditions)
else
find(:all)
end
end
end
I`ve tired set attr_accessible in controller too, in my randomized way.
the Controller:
class CustomersController < ApplicationController
include ActiveModel::MassAssignmentSecurity
attr_accessible :doc, :doc_rg, :name, :birthday, :name_sec, :address, :state_id, :city_id, :district_id, :customer_pj, :is_customer
autocomplete :business_segment, :name, :full => true
autocomplete :business_activity, :name, :full => true
[...]
end
The test, my passed test
describe "accessible attributes" do
it "should allow access to basics fields" do
expect do
#customer.save
end.should_not raise_error(ActiveModel::MassAssignmentSecurity::Error)
end
end
The error:
ActiveModel::MassAssignmentSecurity::Error in CustomersController#create
Can't mass-assign protected attributes: doc, doc_rg, name_sec, address, state_id, city_id, district_id, customer_pj, is_customer
https://github.com/megabga/crm
1.9.2p320
Rails 3.2
MacOS
pg
my bad, in my controller its setting an oldest class. Then old class don`t have attributes passing in parameters. Sorry!