Ruby On Rails Change Column to Null, Not Work? - ruby-on-rails

I command in Terminal to change on column in database to not null, but It seems not work.
rails g migration change_column_null :Speaker, :surname, false
I got a file ChangeColumnNull But inside, it is nothing.
class ChangeColumnNull < ActiveRecord::Migration
def change
end
end
Lecture Controller (Def Create):
class CplecturesController < ApplicationController
layout 'cp_layout'
def create
#lecture = Lecture.new(lecture_params)
#lecture.save
redirect_to #lecture
end
private
def lecture_params
params.require(:lecture).permit(:lecture_title, :lecture_day, :column, :start_time, :end_time, :registered_speakers, :guest_speakers, :description)
end
end
Forms
<%= form_for :lecture, url:lectures_path do |f| %>
<form>
<div class="form-group">
<%=label_tag "Lecture Title" %><br>
<%= f.text_field :lecture_title, :class => "form-control", :placeholder => "Example: Why is Wordpress the best?" %>
</div>

Erase that migration and write a blank migration with a better name and then fill it out by setting a default value. If you have a default value it will never be null.
rails g migration ChangeColumnOnTableName
Then inside that migration do the following:
change_column :name_of_table, :name_of_column, :data_type_of_column, :null => false
If you're only worried about it being null based on what a user enters, you could simply add a validation that requires it. In your model:
validates :name_of_column, presence: true

if you are using latest ruby (2.5+) Here is the migration script to change fields from NOT NULL to NULL
class ChangeEmailPasswordToNullableUsers < ActiveRecord::Migration[5.2]
def change
change_column_null :users, :email, true
change_column_null :users, :password, true
end
end

Related

Validation failed Class must exist

I have been (hours) trouble with associations in Rails. I found a lot of similar problems, but I couldn't apply for my case:
City's class:
class City < ApplicationRecord
has_many :users
end
User's class:
class User < ApplicationRecord
belongs_to :city
validates :name, presence: true, length: { maximum: 80 }
validates :city_id, presence: true
end
Users Controller:
def create
Rails.logger.debug user_params.inspect
#user = User.new(user_params)
if #user.save!
flash[:success] = "Works!"
redirect_to '/index'
else
render 'new'
end
end
def user_params
params.require(:user).permit(:name, :citys_id)
end
Users View:
<%= form_for(:user, url: '/user/new') do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :citys_id, "City" %>
<select name="city">
<% #city.all.each do |t| %>
<option value="<%= t.id %>"><%= t.city %></option>
<% end %>
</select>
end
Migrate:
class CreateUser < ActiveRecord::Migration[5.0]
def change
create_table :user do |t|
t.string :name, limit: 80, null: false
t.belongs_to :citys, null: false
t.timestamps
end
end
Message from console and browser:
ActiveRecord::RecordInvalid (Validation failed: City must exist):
Well, the problem is, the attributes from User's model that aren't FK they are accept by User.save method, and the FK attributes like citys_id are not. Then it gives me error message in browser saying that "Validation failed City must exist".
Thanks
Try the following:
belongs_to :city, optional: true
According to the new docs:
4.1.2.11 :optional
If you set the :optional option to true, then the presence of the
associated object won't be validated. By default, this option is set
to false.
This comes a bit late but this is how to turn off this by default in rails 5:
config/initializers/new_framework_defaults.rb
Rails.application.config.active_record.belongs_to_required_by_default = false
In case you don't want to add optional: true to all your belongs_to.
I hope this helps!
You need to add the following to the end of the belongs_to relationship statement:
optional: true
It is possible to set this on a global level so that it works in the same way as older versions of rails, but I would recommend taking the time to manually add it to the relationships that really need it as this will cause less pain in the future.
I found out a solution to the problem "Validation failed: Class must exist" and it's better than use:
belongs_to :city, optional: true
4.1.2.11 :optional
If you set the :optional option to true, then the presence of the associated object won't be validated. By default, this option is set to false.
cause you still make a validation in application level. I solve the problem making my own validation in create method and changing user_params method:
def create
#city = City.find(params[:city_id])
Rails.logger.debug user_params.inspect
#user = User.new(user_params)
#user.city_id = #city.id
if #user.save!
flash[:success] = "Works!"
redirect_to '/index'
else
render 'new'
end
end
def user_params
params.require(:user).permit(:name)
end
I didn't test this code, but it works in another project mine. I hope it can help others!
Rails 5
If you have a belongs_to relationship to :parent then you have to pass an existing parent object or create a new one then assign to children object.
belongs_to :city, required: false
params.require(:user).permit(:name, :citys_id)
It's a mistake, isn't it? (citys_id vs city_id)
Rails.application.config.active_record.belongs_to_required_by_default = false
This works because the Rails 5 has true by default
to disable you go under Initilizers then click on the New_frame-work and turn the true to false

Ruby on Rails: ActiveRecord::AssociationTypeMismatch

I am getting an ActiveRecord::AssociationTypeMismatch error when trying to submit a record.
Subject(#88982676) expected, got String(#20223000)
View:
<%= f.collection_select :subject, Subject.order(:subject), :subject, :subject, {prompt: "Select a subject"}, {class: "form-control"} %>
Controller:
def create
#homework = current_user.homeworks.build(homework_params)
if #homework.save
redirect_to homeworks_path
else
render 'new'
end
end
...
def homework_params
params.require(:homework).permit(:subject, :description, :date, :completed_at)
end
Model: Homework.rb
class Homework < ActiveRecord::Base
validates :subject, presence:true
belongs_to :subject
def completed?
!completed_at.blank?
end
end
Subject.rb
class Subject < ActiveRecord::Base
has_many :homeworks
def to_s
subject
end
end
This use to work but suddenly doesn't. I did change the name of the table to "subject" and changed the views and controller accordingly. It appears to be looking for id now? Subject is a string. Any advice? Thanks.
According to your association models, your homework attributes should look like this:
subject_id:integer description:string date:datetime completed_at:datetime
Therefore, you should permit subject_id, instead of subject in your homework_params
As for collection_select method, it should be something like this:
f.collection_select :subject_id, Subject.order(:subject), :id, :subject

Rails 4.2.4 ActiveAdmin Globalize show one input only

Here I have a problem when using rails 4.2.4 + activeadmin 0.6.6 + rails-i18n 4.0.8 + globalize 4.0.3 + activeadmin-globalize 1.0.0 .
The problem I am facing is shown in the following image, it only show one input box for me:
In the contact table, I should have more variables as below:
db/migrate/XXXXXXXXX_create_contacts.rb
class CreateContacts < ActiveRecord::Migration
def up
create_table :contacts do |t|
t.string :url
t.boolean :publish, :default => false
t.integer :sequence
t.timestamps null: false
end
end
def down
drop_table :contacts
end
end
db/migrate/XXXXXXXXX_translate_for_contacts.rb
class TranslateForContact < ActiveRecord::Migration
def up
Contact.create_translation_table! :tool => :string, :content => :text
end
def down
Contact.drop_translation_table!
end
end
Contact table is originally generated using scaffold.
:url, :publish, :sequence are the variables common in all locales.
Only :tool and :content need to translate.
In app/models/contact.rb
class Contact < ActiveRecord::Base
active_admin_translates :tool, :content do
validates_presence_of :tool, :content
end
translates :tool, :content
end
In app/admin/contact.rb
ActiveAdmin.register Contact do
permit_params :url, :tool, :content, :publish, :sequence, translations_attributes: [:id, :locale, :tool, :content]
index do
translation_status
default_actions
end
form do |f|
f.translated_inputs "Translated fields", switch_locale: false do |t|
t.input :tool
t.input :content
end
f.actions
end
end
One more related thing, as I have also facing the "missing form_buffers" problem, I have edited the code in the activeadmin-globalize gem as following webpage:
https://github.com/maxime-carbonneau/activeadmin-globalize/commit/734f375152982ccde12e7810760a7ab82c8d4a20
but I am not sure if this edit will cause the problem.
Before I install and use activeadmin-globalize, I am sure there are the input boxes for :url, :publish, :sequence.
Do anyone have the solution or know what's happened? Thanks!
----------------Final Solution--------------------
As activeadmin-globalize is not maintained, most of it function not work normally. I recommend using another gem for it.
In the docs for the activeadmin-globalize gem, the author on Dec 9, 2014 warned users that he's not maintaining the gem anymore and to take it as you will. You may want to consider dropping the gem.
But, as activeadmin is concerned, I believe the reason your not seeing any other form inputs on your page is because you have haven't included them in your code below
# app/admin/contact.rb
...
form do |f|
f.translated_inputs "Translated fields", switch_locale: false do |t|
t.input :tool
t.input :content
end
f.actions
end
If you want to include them back in you will either need to just remove that entire block of code altogether and let activeadmin create the default form inputs for you or you can individually add your inputs back in
# app/admin/contact.rb
...
form do |f|
f.translated_inputs "Translated fields", switch_locale: false do |t|
t.input :url
t.input :tool
t.input :content
t.input :publish
...
end
f.actions
end

Rails Country_select can't save to database

I am having trouble integrating this select country plug in (https://github.com/scudco/country_select_test) into my test application. I installed it and put it into my database. It shows up when I type my id into the rails console but it always comes up as nil. Here is my view.haml:
.form-group
= f.input :country_code, autofocus: true, :class => "form-control"
.form-group
= f.input :address, autofocus: false, :class => "form-control"
Here is the migration I recently made:
class AddCountryCodeToUsers < ActiveRecord::Migration
def change
add_column :users, :country_code, :string
end
end
The output of my console:
updated_at: "2015-08-07 15:29:26", address: " ", country_code: nil>
I have nothing about the :country_code in my users.rb file. I used to have the assert country_code in their but it didn't change anything when I took it out. Thank you to everyone who helps me out. I'm still a noob at ruby on rails.
You probably miss to allow the :country_code param in your UsersController due to strong_parameters
In your controller you should have something like
def users_params
params.require(:user).permit(...)
end
You need to ensure, in the permit method, that :country_code is called too. For example:
params.require(:user).permit(:country_code, :email, :password, :password_confirmation)

Rails money gem and form builder

I'm having an issue with the forms and the money gem.
This is my problem:
I create a record which has an "amount" field (mapped to money object). Let's say I enter 10 (dollars).
The money gem converts it to 1000 (cents)
I edit the same record and the form pre-populates the amount field as 1000
If I save the record without changing anything, it will convert the 1000 (dollars) to 100000 (cents)
How do I make it display the pre-populated amount in dollars instead of cents?
Edit:
I tried editing the _form.html like this:
= f.text_field(:amount, :to_money)
and I get this error:
undefined method `merge' for :to_money:Symbol
Given a migration as follows:
class CreateItems < ActiveRecord::Migration
def self.up
create_table :items do |t|
t.integer :cents
t.string :currency
t.timestamps
end
end
def self.down
drop_table :items
end
end
And a model as follows:
class Item < ActiveRecord::Base
composed_of :amount,
:class_name => "Money",
:mapping => [%w(cents cents), %w(currency currency_as_string)],
:constructor => Proc.new { |cents, currency| Money.new(cents || 0, currency || Money.default_currency) },
:converter => Proc.new { |value| value.respond_to?(:to_money) ? value.to_money : raise(ArgumentError, "Can't conver #{value.class} to Money") }
end
Then this form code should work perfectly (I just tested under Rails 3.0.3), properly displaying and saving the dollar amount every time you save/edit. (This is using the default scaffold update/create methods).
<%= form_for(#item) do |f| %>
<div class="field">
<%= f.label :amount %><br />
<%= f.text_field :amount %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
You can now edit monetized fields directly (money-rails 1.3.0):
# add migration
add_column :products, :price, :price_cents
# set monetize for this field inside the model
class Product
monetize :price_cents
end
# inside form use .price instead of .price_cents method
f.text_field :price
See https://stackoverflow.com/a/30763084/46039
If you have multiple money fields in your table and you can't name them all "cents".
class CreateItems < ActiveRecord::Migration
def self.up
create_table :items do |t|
t.integer :purchase_price_cents
t.string :currency
t.timestamps
end
end
def self.down
drop_table :items
end
end
which would change your model to
class Item < ActiveRecord::Base
composed_of :purchase_price,
:class_name => "Money",
:mapping => [%w(purchase_price_cents cents), %w(currency currency_as_string)],
:constructor => Proc.new { |purchase_price_cents, currency| Money.new(purchase_price_cents || 0, currency || Money.default_currency) },
:converter => Proc.new { |value| value.respond_to?(:to_money) ? value.to_money : raise(ArgumentError, "Can't convert #{value.class} to Money") }
end
monetizing and the simple form, the steps as follows:
Migration
add_monetize :table, :amount
Model with validation
monetize :amount_cents, allow_nil: true, numericality: {greater_than: 0}
Controller permit params (dont use amount_cents here)
params.require(:model).permit(:amount)
simple form input
when it's saved it will be saved in cents in amount_cents column in db

Resources