Ruby on Rails updating specific column based on another table value - mysql

I am working with a Ruby on Rails test site that is basically a carbon copy of our actual site. Upon updating user data, I have noticed in both test and the live environment that the user table has both department_id and department_name in it, rather than just joining on department_id and always pulling the info from the department table. The existing code updates department_id in the users table when someone switches departments, but the department_name is not updated. How this was never realized I'm not sure, because there are a few places that pull department_name from the users table directly where I've manually updated the incorrect department_name fields. What do I need to do in the users controller to get it to update the department_name in the user table based on what is in the department table for that department_id? (I know I could recreate the pages to join on the department_id and pull the name from the dept table instead, but I really don't feel like rewriting a bunch of different pages).
users_controller.rb update method
def update
#user = User.find(params[:id])
email_changed = #user.email != params[:user][:email]
#need to set user's department_name so it is updated in users table
#user.update_without_password(params[:user])
successfully_updated = true
if successfully_updated
flash[:notice] = "Profile was successfully updated"
redirect_to #user
else
render "edit"
end
end
Form Control that allows department change in users/_form.html.erb
<% if current_user.is_admin? %>
<%= f.association :department, label: false, :collection =>
#departments, :prompt => "Select Department" %>
...
Model file
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me,
:username, :first_name, :middle_name, :last_name, :suffix, :department_id,
:department_name
belongs_to :department
...

In your User model:
before_save do
self.department_name = department.name if department_id_changed?
end

Related

Trying to relate tables in MySQL and Rails

I'm having problems relating some tables, I have the client table with the fields ("name, age and gender") and another table called personal_documents with the fields "cpf, rg, etc ...), I tried the relationship of personal_documents belongs_to client but when i search for client only the fields of client ("name, age and gender) and "personal_documents_id" appear, the fields for personal documents ("cpf, rg, etc...) should also appear too, thanks for the help!
Code:
In client model:
has_one :personal_documents
in personal_documents model:
belongs_to :client
rails generate model Client
inside migration file you create as follow
class CreateClients < ActiveRecord::Migration[6.0]
def change
create_table :clients do |t|
t.string :user_kind
# your other field here
t.timestamps
end
end
end
rails generate model PersonalDocument
inside migration file you create as follow
class CreatePersonalDocuments < ActiveRecord::Migration[6.0]
def change
create_table :personal_documents do |t|
# this is the one that relate personal document
# to client
t.references :client, index: true
t.string :rg_front
# other field
t.timestamps
end
end
end
inside model you can declare as follow
class Client < ApplicationRecord
# please note personal_document in singular
has_one :personal_document, dependent: :destroy
accepts_nested_attributes_for :personal_document, allow_destroy: :true
# now you can do some like above for disponibility, personal_document_legal, bank_information
end
class PersonalDocument < ApplicationRecord
belongs_to :client
end
inside your controller you declare as follow
class ClientsController < ApplicationController
def barang_params
params.require(:client).permit(
:user_kind,
personal_document_attributes: [
:id,
:rg_front,
:rg_back,
:cpf,
:cnh_front,
:cnh_back,
:bank_card_front,
:address_proof,
:profile_picture
]
# this from your other question, and I think it's already correct
)
end
end
To access personal_documents of client
Client.find(1).personal_documents.cpf
To access client of personal_documents
PersonalDocument.find(id).client.name
both
document = PersonalDocument.find(id)
client = document.client
or
client = Client.find(1)
document = client.personal_documents
document.cpf
client.name
additionaly change :has_one to singular personal_document

Delete an element from a collection

I'm facing to a stupid problem. I have created a collection select which is creating elements into a join table "staffs_task" to reference an association between the model staff and task.
And now I would like two things: (1) a button delete this association (2) and a little bit of code for my model staffs_task to avoid duplication, so with the task_id and staff_id. And last info, task is a model built by ranch
my code:
(the collection in new_task)
<%= select_tag "staffs_task", options_from_collection_for_select(#staffs, 'id', 'name') , :multiple => true %>
(task_controller)
skip_before_action :configure_sign_up_params
before_action :set_ranch
before_action :set_task, except: [:create]
def create
#task = #ranch.tasks.create(task_params)
#staffs = Staff.where(:id => params[:staffs_task])
#task.staffs << #staffs
if #task.save
#task.update(done: false)
#task.update(star: false)
flash[:success] = "The task was created "
else
flash[:success] = "The task was not created "
end
redirect_to #ranch
end
private
def task_params
params.require(:task).permit(:content, :deadline, :row_order, :date, :assigned_to)
end
def set_ranch
#ranch = Ranch.find(params[:ranch_id])
end
def set_task
#task = #ranch.tasks.find(params[:id])
end
So if you have any idea about one of this two things, your help would be welcome
Thanks in advance !!
Lets say you have the following many to many setup with a join model:
class Staff
has_many :assignments
has_many :tasks, through: :assignments
end
class Task
has_many :assignments
has_many :staff, through: :assignments
end
class Assignment
belongs_to :task
belongs_to :staff
end
Note that the plural of staff is staff - unless you are talking about the sticks carried by wizards.
ActiveRecord creates "magical" _ids setters for all has_many relationships. When used with a has_many through: relationship rails is smart enough to just remove the rows from the join table.
You can use this with the collection_select and collection_checkboxes methods:
<%= form_for([#task.ranch, #task]) do |f| %>
<%= f.collection_select(:staff_ids, Staff.all, :id, :name, multiple: true) %>
<% end %>
You would then set your controller up like so:
def create
#task = #ranch.tasks.new(task_params) do |t|
# this should really be done by setting default values
# for the DB columns
t.done = false
t.star = false
end
if #task.save
redirect_to #ranch, success: "The task was created"
else
render :new, error: "The task was not created"
end
end
private
def task_params
params.require(:task)
.permit(:content, :deadline, :row_order, :date, :assigned_to, staff_ids: [])
end
staff_ids: [] will allow an array of scalar values. Also not that .new and .create are not the same thing! You where saving the record 4 times if it was valid so the user has to wait for 4 expensive write queries when one will do.

Rails cannot update column value

I have created Rails(version 3.2) application with mysql database. I have table Message with column content. I can update the following data using rails console but I can't using run same code from seeds.rb.
data: "Join **** Audio / Video Meeting. This is an online meeting by ****, the community marketplace to find products and services in your neighbourhood. http://*****.dev:3000/conferences/80"
I have following code in my seeds.rb file
all_messages = Message.all
all_messages.each do |message|
message_content = message.content
if message_content.present? && message_content[/\/(.*)\/(.*)\/conferences/,2].present?
message_content.slice! (message_content[/\/(.*)\/(.*)\/conferences/,2]+'/')
if message.update_attributes!(content: message_content)
puts message.content
else
puts "nothing"
end
end
end
It does't show any errors, but data is not updated in db and not shown any errors.
This is my model file
class Message < ActiveRecord::Base
attr_accessible :content
after_save :update_conversation_read_status
belongs_to :sender, :class_name => "Person"
belongs_to :conversation
has_one :request
validates_presence_of :sender_id
validates_presence_of :content
def update_conversation_read_status
conversation.update_attribute(:last_message_at, created_at)
conversation.participations.each do |p|
last_at = p.person.eql?(sender) ? :last_sent_at : :last_received_at
p.update_attributes({ :is_read => p.person.eql?(sender), last_at => created_at})
end
end
end
Note: content is text type in db.

Mongoid embedded documents and Rails strong parameters not working

I have a 1-N relationship in Mongoid/Rails:
class Company
include Mongoid::Document
field :name, type: String
embeds_many :people, class_name: 'Person'
end
class Person
include Mongoid::Document
field :first_name, type: String
embedded_in :company, class_name: 'Company', inverse_of: 'people'
end
Now I can successfully create a Company as follows in the console; for example:
> c = Company.new(name: 'GLG', :people => [{first_name: 'Jake'}]) # OK!
> c.people # OK!
Then I have a JSON API controller to update a company, along the lines of:
# PUT /api/companies/:id
def update
if Company.update(company_params)
# ... render JSON
else
# ... render error
end
end
private
def company_params
params.require(:company).permit(:name, :people => [:first_name])
end
Now, when the PUT request comes in from the frontend, the company_params is always missing the :people attribute. Rails log says:
Parameters: {"id"=>"5436fbc64a616b5240050000", "name"=>"GLG", "people"=>[{"first_name"=>"Jake"}], "company"=>{"name"=>"GLG"}}
I don't get an "Unpermitted parameters" warning. I've tried every conceivable way of permitting the people field and it still doesn't get included.
params.require(:company).permit!
Results in the same. What am I doing wrong?
You have to accept nested_attributes on assignment
class Company
include Mongoid::Document
field :name, type: String
embeds_many :people, class_name: 'Person'
accepts_nested_attributes_for :people
end

Rails 4 Devise First Name, Last Name Not Going to DB

I setup a devise on my rails 4 application. I followed this tutorial https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address and added the username value. I also wanted First Name and Last Name, so I assumed it was something close to the tutorial. I followed SOME of the parts and skipped the authentication parts, and update the views. It is somewhat working. When registering the fields show up and when you fill up, they pass all check but they DO NOT get entered in the DB. It just shows up NULL for the First name and Last name, but username is actually working. Here are the steps that I did.
I followed the whole tutorial (except for the last part about gmail and me.com).
I added the First Name and Last Name fields:
I ran the commands
rails generate migration add_firstname_to_users first_name:string:uniq
rails generate migration add_lastname_to_users last_name:string:uniq
Then did rake db:migrate. Then I added the fields to application controller to permit the fields. Here is my full application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:first_name, :last_name, :username, :email, :password, :password_confirmation, :remember_me) }
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:login, :username, :email, :password, :remember_me) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:first_name, :last_name, :username, :email, :password, :password_confirmation, :current_password) }
end
end
Then I added the firstname and lastname to the attr_accessor. Here is my full user.rb model.
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
attr_accessor :login, :first_name, :last_name
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :authentication_keys => [:login]
def self.find_first_by_auth_conditions(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
else
where(conditions).first
end
end
end
Then I updated my views and added <%= f.text_field :first_name %> and <%= f.text_field :last_name %> to the registrations new and registrations edit views.
The fields show up and have no errors when submitting the form. They just do not update the DB. I added the name manually in the MYSQL database through PHPMyAdmin and then went to the edit page and it grabs it correctly. It would be great if you could help. Thanks! :)
Try to remove it from attr_accessor because attr_accessor works like instance variable
http://apidock.com/ruby/Module/attr_accessor