Do I need to update an attribute in rails? (and how?) - ruby-on-rails

I generated scaffolding for a class: ExpenseReport
One of the attributes was type - which I created a selct for, where two options where possible: Major and Regular.
When submitting the form to create a report, I was pulling this error:
Invalid single-table inheritance type: Regular is not a subclass of ExpenseReport
My assumption was - "Okay, let's just not have an attribute called type, it looks like that may be causing problems." So I created a migration, renaming type to "report type" and raked (see migration and proof of rake below)
Migration
class UpdaeColumnName < ActiveRecord::Migration
def change
rename_column :expense_reports, :type, :report_type
end
end
Proof of Rake
Drews-MacBook-Pro:depot drewwyatt$ rails generate migration UpdaeColumnName
invoke active_record
create db/migrate/20130820215925_updae_column_name.rb
Drews-MacBook-Pro:depot drewwyatt$ rake db:migrate
== UpdaeColumnName: migrating ================================================
-- rename_column(:expense_reports, :type, :report_type)
-> 0.0021s
== UpdaeColumnName: migrated (0.0021s) =======================================
Now, however, it never ever saves my input, and fires validation with every submit - telling me "Report type is not included in the list", is there another attribute name I need to update or something?
Relevant _form.html.erb
<div class="field">
<%= f.label :report_type %><br>
<%= f.select :report_type, ExpenseReport::TYPES,
prompt: "select one" %>
</div>
Model
class ExpenseReport < ActiveRecord::Base
validates :place_of_purchase, :items, :reason, :estimated_cost,
:requestor_name, presence: true
TYPES = [ 'Major', 'Regular' ]
validates :report_type, inclusion: TYPES
SITES = [ '001 (Lubbock)', '002 (Odessa)', '003 (Midland)', '004 (Lubbock)' ]
validates :site, inclusion: SITES
end

The attribute "type" is for single table inheritance, more about can be found here: http://railscasts.com/episodes/394-sti-and-polymorphic-associations or here: http://rails-bestpractices.com/posts/45-use-sti-and-polymorphic-model-for-multiple-uploads
If you stay with your new report_type, you should change your scaffold stuff. Are you on rails 4? If yes, change your private expense_report_params method in your expense_reports_controller.rb
Should be something like that:
def expense_report_params
params.require(:expense_report).permit(:place_of_purchase, :items, :reason, :estimated_cost, :requestor_name, :other_attributes, :type)
end
Change it to:
def expense_report_params
params.require(:expense_report).permit(:place_of_purchase, :items, :reason, :estimated_cost, :requestor_name, :other_attributes, :report_type)
end
In rails 4 you always have to permit your params..otherwise it would not work. If you permit a params "type" which does not exist, you´ll get an error..

Related

Is it possible to prevent empty action text entries

I have a very simple action text model and form
class Course < ApplicationRecord
validates :title, presence: true
has_rich_text :content
end
<%= form_with model: #course do |f| %>
<%= f.text_field :title %>
<%= f.rich_text_area :content %>
<% end %>
It's all working great but since the content field is optional is it possible to create a course model without creating action_text_rich_texts entries that are empty/blank? Even if the user only enters the title without any content it's currently creating them and there's a lot of unnecessary and empty action_text_rich_texts rows in the database
The way I handled this in my application is with a before_save callback that removes the ActionText::RichText database record if the body is blank.
This avoids polluting the controller and works on both create and update actions. The body attribute of the action_text attribute is still accessible even without a corresponding database record, because ActionText will instantiate a new object if the record cannot be found (which allows you to test for blank? in either scenario).
Try this:
class Course < ApplicationRecord
validates :title, presence: true
has_rich_text :content
before_save :clean_up_content
private
def clean_up_content
self.content.destroy if self.content.body.blank?
end
end
I'm not sure about anything built into Actiontext for this, but I would imagine you could handle this at the controller level.
The first thing I would try is to see if not setting anything to content prevents Rails from creating an associated record:
class CourseController
def create
# remove course_params[:content] if it's blank
course_values = course_params[:content].blank? ? course_params.except(:content) : course_params
Course.create(course_values)
...
end
end
Extending Eric Powell's approach:
# app/models/concerns/do_not_save_blank_rich_text.rb
module DoNotSaveBlankRichText
extend ActiveSupport::Concern
included do
before_validation :do_not_save_blank_rich_text
end
private
def do_not_save_blank_rich_text
rich_text_attributes = self.class.reflections.values.select do |reflection|
reflection.options[:class_name] == "ActionText::RichText"
end.map(&:name)
rich_text_attributes.each do |rich_text_attribute|
if self.public_send(rich_text_attribute) && self.public_send(rich_text_attribute).body.blank?
self.public_send(rich_text_attribute).mark_for_destruction
end
end
end
end

undefined method `model_name' for #<Class:0x007f043631a380>

I ran through similar problems here but nothing seems to match my problem. I got the error undefined method model_name for #<Class:0x007f043631a380>. It points to line #1 of my /app/views/classes/new.html.erb file:
<%= form_for #class do | f | %>
<div class = “form-group”>
<%= f.label :name %>
<%= f.text_field :name, class: ‘form-control’ %>
My app/controllers/classes_controller.rb:
class ClassesController < ApplicationController
def new
#class = Class.new
end
end
My app/models/class.rb:
class Class < ActiveRecord::Base
validates :name, presence: true
validates :teacher, presence: true
validates :day, presence: true
validates :start_time, presence: true
validates :duration, presence: true, numericality: { only_integer: true }
end
I am very new to RoR and don't really know where to look for a problem. Could you give me direction?
Your code seem good. It is probably because class is a reserved word in rails : https://reservedwords.herokuapp.com/
Try to name your models and controllers something that would not look like some ruby code.
EDIT: What Roman says is correct. Your controller is always plural. Try renaming your controller first as ClassesController.
The Class.new line is probably unintentionally referencing the Ruby class Class. You could try namespacing your Class, for instance:
module MyModels
class Class < ActiveRecord::Base
end
end
and then using MyModels::Class would probably work, but I try to avoid naming things Class. I'm not sure, since you have 2 classes at the root named the same if there's any other way to specify which you're referencing, and if you specifically require and re-define Class, I'm not even sure what types of problems would ensue, but I'm sure it wouldn't be my ideal afternoon.
One thing that I often see done, when the name is needed, is to name custom Class classes and class variables as Klass and klass. Most coders (that I know, at least), wouldn't even blink twice seeing something like that named with a K.
Make sure your controller and views name is plural. Try ClassesController and views/classes/new.html.erb.
You can not use a reserved keyword in rails and ruby as your model name.
Your class name should be like SchoolClass or something like that.

ActiveAdmin Globalize create index filters

I'm using Globalize and ActiveAdmin, and I've now installed a gem from a fork of ActiveAdminGlobalize
Everything that is described in the readme is working, but I'd like to add a filter to the Active Admin Index.
So, for the model stuff.rb
class Stuff < ApplicationRecord
translates :name
active_admin_translates :name do
validates_presence_of :name
end
end
And the class in app/admin/stuff.rb
ActiveAdmin.register Stuff do
index do
translation_status
column :name
end
filter :name
end
How do I make the filter :name to work?
Thanks
I'm using the regular ActiveAdmin gem and, after scratching my head for quite some time, found that the following works:
filter :translations_name_contains, as: :string
Of course you can change name with any other attributes you have translated with Globalize
filter :translations_title_contains, as: :string
To tie everything up nicely, I like to customize the label to avoid the default one AA creates:
filter :translations_title_contains, as: :string, label: "Search", placeholder: "Search page title..."
Hope this helps, thanks!

Simple way in ruby to ignore error if object doesn't exist

I have two objects: Wine, Brand
Brand has_many :wines
Wine belongs_to :brand
How can I simplify the following code:
<%= #wine.brand.name if #wine.brand %>
I realize it's already very simple, but I have some different complexities in my code that make this cumbersome. What I'd like to do is something along the lines of:
<%= &#wine.brand.name %>
Where it basically ignores the error. In PHP you can do this, I just can't find a corollary for ruby.
You can use try method:
<%= #wine.brand.try(:name) %>
I'd rather do this as follows:
class Wine
def brand_name
brand.present? ? brand.name : ''
end
end
This keeps your view slightly cleaner:
<%= #wine.brand_name %>
You can use delegate:
class Wine < ActiveRecord::Base
belongs_to :brand
delegate :name, to: :brand, prefix: true, allow_nil: true
end
This creates a Wine#brand_name method, returning either the brand's name or nil if brand does not exist.

Elegant way to process collection_select in controller?

I am currently somewhat stuck figuring out an elegant solution to my following
problem:
Let's say I have the following classes:
class Event < ActiveRecord::Base
belongs_to :reg_template, :class_name => "EmailTemplate"
[...]
end
class EmailTemplate < ActiveRecord::Base
has_many :events
[...]
end
And a view that contains:
<%= f.collection_select(:reg_template_id, EmailTemplate.all, :id, :name) %>
What is the recommended way of processing this form field in an action
controller?
Having a 1:1 relationship between Event and EmailTemplate means that Rails
does not generate a reg_template_id and reg_template_id= method (as it would
do for a 1:n relationship), so attempts to read or assign this field will fail
with
unknown attribute: reg_template_id
when attempting to call
Event.update_attributes
Using
<%= f.collection_select(:reg_template, EmailTemplate.all, :id, :name) %>
instead also does not help much as it will fail with:
EmailTemplate(#70070455907700) expected, got String(#70070510199800)
I guess I must be missing something terribly obvious as I think is is rather
common to update a model instance with a reference to another object through a
collection_select.
If you have the column reg_template_id in the events table, then the following code should work:
<%= f.collection_select(:reg_template_id, EmailTemplate.all, :id, :name) %>

Resources