I'm making an app using Rails. I have 4 boolean columns in a table lilke below, and I want to show a message if that column is true.
class CreatePosts < ActiveRecord::Migration[5.2]
def change
create_table :posts do |t|
t.integer :user_id, null: false, default: 0
t.string :title, null: false, default: ''
t.text :description, null: true
t.boolean :tag_1, null: false, default: false
t.boolean :tag_2, null: false, default: false
t.boolean :tag_3, null: false, default: false
t.boolean :tag_4, null: false, default: false
t.timestamps
end
end
posts_controller.rb
def index
#posts = Post.all
end
index.html.erb
<% #posts.each do |post| %>
<ul>
<% if post.tag_1 %>
<li><%= 'tag_name_A' %></li>
<% end %>
<% if post.tag_2 %>
<li><%= 'tag_name_B' %></li>
<% end %>
<% if post.tag_3 %>
<li><%= 'tag_name_C' %></li>
<% end %>
<% if post.tag_4 %>
<li><%= 'tag_name_D' %></li>
<% end %>
<% if !post.tag_1 && !post.tag_2 && !post.tag_3 && !post.tag_4 %>
<li>none</li>
<% end %>
</ul>
<% end %>
So 'tag_name_A' will be shown if tag_1 is the only true column, and there'll be 'tag_name_B' & 'tag_name_D' shown if tag_2 and tag_4 are both true. (I hope I'm making myself clear.)
These codes are actually working fine and I'm already getting what I want, but I just don't like how they are written. It looks messy and obviously not smart. (You can tell that I'm a newbie.) Is there a better way to rewrite them?
Related
What is the best and correct way to setup a simple_forms_for field that contains a collection for a select field but the values to be contained in the select need to be sourced from a model that does not have a direct association to the calling fields model?
For example I have a simple_forms_for form like follows:
<%= simple_form_for(#customer) do |f| %>
<%= f.error_notification %>
<fieldset>
<div class="form-inputs">
<%= f.input :code, required: true %>
<%= f.input :name, required: true %>
<%= f.input :location, required: true %>
<%= f.input :service_level %>
<%= f.input :golive_date, :as => :date_picker %>
<%= f.input :connection_type %>
<%= f.input :service_centre %>
<%= f.input :end_date, :as => :date_picker %>
<%= f.input :sla %>
<%= f.input :project_code %>
</div>
<div class="form-actions">
<%= f.button :submit, :class => "btn btn-primary" %>
</div>
</fieldset>
<% end %>
I want to make the :service_level field a selection field and add a collection to it, however the table that stores the lookup values is not associated with the Customer table for the form.
class Lookup < ActiveRecord::Base
validates_presence_of :name, :description
has_many :lookup_values
accepts_nested_attributes_for :lookup_values, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
class LookupValue < ActiveRecord::Base
belongs_to :lookup
end
class CreateLookups < ActiveRecord::Migration
def change
create_table :lookups do |t|
t.string :name
t.string :description
t.timestamps
end
end
end
class CreateLookupValues < ActiveRecord::Migration
def change
create_table :lookup_values do |t|
t.integer :lookup_id
t.string :name
t.string :value
t.timestamps
end
end
end
I basically want to be able to populate the values of the select using the following SQL query:
select v.name||' - '||v.value
from lookup_values v,
lookups l
where v.lookup_id = l.id
and l.name = 'Service level';
The actual value that is saved into the :service_level field needs to be the value of v.name.
All of the collections examples I have seen only appear to show how to create selects based on models that have an association between them, just wondering if there is an easy way to achieve this without an association.
Ok, well this is embarrassing...
Simple solution was to modify the _form.html.erb view file so that the :service_level field reads as:
<%= f.input :service_level, :collection => LookupValue.joins(:lookup).where(lookups: { :name => 'Service level' }).pluck(:name) %>
I probably need to make this more DRY when repeating for multiple lookup values in the form.
Any ideas how I can enhance this code to:
Remove the blank value that is listed in the select field drop down?
Modify the value text that displays in the select drop down to be
Name ||' - '||value. For example show the values in the format
"L1 - Level 1". The actual value selected and saved would need to
remain as "L1" (the :name value)
Firstly this is the first time I have ever tried to use accepts_nested_attributes_for, so I am still learning and hopefully I have just missed something small.
So I have setup and follow an example for doing accepts_nested_attributes_for but I keep getting a ActiveModel::MassAssignmentSecurity::Error at /reports Can't mass-assign protected attributes: deployment
and I can't figure out why, any help would be grateful code is below:
Report Model:
class Report < ActiveRecord::Base
attr_accessible :name, :weekending, :visable, :deployments_attributes
has_many :deployments, dependent: :destroy
accepts_nested_attributes_for :deployments, allow_destroy: true
end
Deployments Model:
class Deployment < ActiveRecord::Base
attr_accessible :deployment_comments, :deployment_name, :environment, :report_id
belongs_to :report
end
report/new.html.erb
<%= form_for (#report) do |f| %>
<%= render 'shared/error_messages' %>
<h4>Reprot Detials</h4>
<%= f.label "Report Written By: " %> <%= f.text_field :name %><br>
<%= f.label "Weekending: " %> <%= f.text_field :weekending %><br>
<%= f.label "Visable: " %> <%= f.text_field :visable %><br>
<%= f.fields_for :deployment do |builder| %>
<%= render 'reports/forms/deployment_fields', f: builder %>
<% end %><br><br>
<%= f.submit class: "btn btn-large btn-primary" %>
<% end %>
report/forms/_deployment_fields.html.erb
<h4>Deployments</h4>
<%= f.label :deployment_name, "Name of Deployment:" %><br />
<%= f.text_field :deployment_name %><br />
<%= f.label :environment, "Environment of Deployment:" %><br />
<%= f.text_field :environment %><br />
<%= f.label :deployment_comments, "Deployment Comments:" %><br />
<%= f.text_area :deployment_comments %><br />
Reports Controller:
class ReportsController < ApplicationController
def index
#reports = Report.paginate(:page => params[:page],
:per_page => 20,
:order => 'Weekending desc')
end
def show
#report = Report.find(params[:id])
end
def new
#report = Report.new
end
def create
#report = Report.new(params[:report])
if #report.save
redirect_to reports_url
else
render 'new'
end
end
DB Migrations:
timestamp_create_deployments.rb
class CreateDeployments < ActiveRecord::Migration
def change
create_table :deployments do |t|
t.string :environment
t.integer :report_id
t.string :deployment_name
t.string :deployment_comments
t.timestamps
end
add_index :deployments, [:report_id]
end
end
timestap_create_reports.rb
class CreateReports < ActiveRecord::Migration
def change
create_table :reports do |t|
t.date :weekending, :null => false
t.string :name, :null => false
t.boolean :visable, :default => false, :null => false
t.timestamps
end
end
end
So figured it out, once I changed
<%= f.fields_for :deployment do |builder| %>
to
<%= f.fields_for :deployments do |builder| %>
I found that the deployments fields didnt show, so then I added
#report.deployments.build
to my new method of my report controller!
I'll just need to figure out if I need to do anything to the update/edit method or not?
I have a simple model for suggestions in my Rails 3 application. I am trying to add a simple link_to link on the index view that when clicked marks the suggestion as approved.
So far I have the following code:
routes.rb
resources :suggestions do
get :approve
end
suggestions_controller.rb
def approve
#suggestion = Suggestion.find(params[:id])
#suggestion.update_attribute(:approved, 'true')
#suggestion.update_attribute(:approved_on, Time.now)
redirect_to suggestion_path
end
suggestion.rb
attr_accessible :author, :details, :localip, :title, :approved, :approved_on
schema.rb
create_table "suggestions", :force => true do |t|
t.string "title"
t.string "author"
t.text "details"
t.string "localip"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.boolean "approved", :default => false
t.datetime "approved_on"
end
index.html.erb (suggestions)
<% if #suggestion.approved? %>
<%= #suggestion.approved_on %>
<% else %>
Not yet approved. (<%= link_to "Approve", approve_suggestion_url(#approve), :method => :put %>)
<% end %>
When using the above code, I get the following exception error:
undefined method `approved?' for nil:NilClass
Am I missing a step out somewhere something?
Most probably, the code you have posted is inside an each loop like
<% #suggestions.each do |suggestion| %>
...
<% if #suggestion.approved? %>
<%= #suggestion.approved_on %>
<% else %>
Not yet approved. (<%= link_to "Approve", approve_suggestion_url(#approve), :method => :put %>)
<% end %>
<% end %>
You need to use suggestion variable instead of #suggestion instance variable. Also, to construct suggestion approve url, you'll need to use suggestion instead of #approve. Code should be like
<% if suggestion.approved? %>
<%= suggestion.approved_on %>
<% else %>
Not yet approved. (<%= link_to "Approve", approve_suggestion_url(suggestion), :method => :put %>)
<% end %>
Also, you should modify your routes.rb to reflect that approve action is a member action.
resources :suggestions do
put :approve, on: :member
end
To understand the difference between member and collection routes, read difference between collection route and member route in ruby on rails?.
I am trying (unsuccessfully) to setup Authlogic for my Rails3 project. In the user_sessions#new view, I keep getting the following error:
undefined method `login' for #<UserSession: no credentials provided>
Extracted source (around line #7):
5: <%= form_for(:user_session, :url => user_session_path) do |f| %>
6: <%= f.label :login %><br>
7: <%= f.text_field :login %><br>
8: <%= f.password_field(:password) %>
9: <%= f.submit %>
10: <% end %>
I believe that the error is coming because Authlogic is failing to detect which database column should be used for the login field.
I was under the understanding that Authlogic is supposed to fall back on the :email column if no login column is present. For belt and braces I tried adding a config option to the User class but it still did not solve the problem
Here is my code:
User model
class User < ActiveRecord::Base
attr_accessible :password, :password_confirmation
acts_as_authentic do |c|
c.login_field = :email
end
end
UserSessions controller
class UserSessionsController < ApplicationController
def new
#user_session = UserSession.new
end
# ...
end
UserSessions#new view
<%= form_for(:user_session, :url => user_session_path) do |f| %>
<%= f.label :login %><br>
<%= f.text_field :login %><br>
<%= f.password_field(:password) %>
<%= f.submit %>
<% end %>
UserSession model
class UserSession < Authlogic::Session::Base
# configuration here, see documentation for sub modules of Authlogic::Session
end
DB Schema (for authlogic tables)
create_table "sessions", :force => true do |t|
t.string "session_id", :null => false
t.text "data"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
create_table "users", :force => true do |t|
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
t.string "first_name"
t.string "last_name"
t.string "crypted_password"
t.string "password_salt"
t.string "persistence_token"
end
Why won't Authlogic use the login column I tell it to (or is this even the problem)?
You're telling AuthLogic to use the email field, but then using the login field in your view instead. Change your view to:
<%= form_for(:user_session, :url => user_session_path) do |f| %>
<%= f.label :email %><br>
<%= f.text_field :email %><br>
<%= f.password_field(:password) %>
<%= f.submit %>
<% end %>
and it should work.
This error can actually occur for multiple reasons. The one that affects me most often is NOT having the users table created.
I want to use the boolean attribute is_white from my inner_object to switch between html code in the the partial _inner_object_form_fields. This is my attempt.
<%= form_for #outer_object do |f| %>
<%= f.fields_for :inner_object do |builder| %>
<%= render :partial => "inner_object_form_fields", :locals => { :f => builder } %>
<% end %>
<% end %>
This is my attempt of the partial _inner_object_form_fields.
<% if f.is_white == true %>
<%= f.label(:name, "White") %>
<% else %>
<%= f.label(:name, "Black") %>
<% end %>
This is the migration file of InnerObjects.
class InnerObjects < ActiveRecord::Migration
def self.up
create_table :inner_objects do |t|
t.string "name"
t.boolean "is_white", :default => true
t.timestamps
end
end
def self.down
drop_table :inner_objects
end
end
I found a similar question but could not retrieve an answer for me.
The question is: How can access the attribut is_white? My example does NOT work.
Try
<% if f.object.is_white == true %>
Seem to remember you could access the object this way (not 100% sure though ;)
Is it because f.is_white is based on a blank object in the partial? Try
<%= form_for #outer_object do |f| %>
<%= f.fields_for f.inner_object do |builder| %>
<%= render :partial => "inner_object_form_fields", :locals => { :f => builder } %>
<% end %>
<% end %>
That way it's referencing the attached object and any state you've created.
Even one step further would be to do something like this:
<%= f.fields_for f.inner_object do |builder| %>
<%= render :partial => "inner_object_form_fields", :locals => { :f => builder, :inner_object => builder.object } %>
<% end %>
Then you can do.
<% if inner_object.is_white == true %>
This way your partials code looks a little cleaner.