Ruby on Rails Update field of all users - ruby-on-rails

I'm having a bit of trouble and I'm not sure if it's even possible to do what I want.
I have a user model with a field called points. I also have a matches model.
I've been trying to use my matches_controller to update the points field of every user when a match gets updated (by a site admin). The goal is to add points if the user selected the correct score.
I'm not sure if I'm able to do this. I'm wondering am I incorrect trying to access the user model from the matches_controller? Because I want to update all fields when a match score is updated, I need to do it from the matches_controller
I've been going around in circles trying to solve this. Am I approaching it incorrectly?
Thanks for reading and hopefully helping.
Here's the relevant code
matches_controller.rb
def update
respond_to do |format|
if #match.update(match_params)
format.html { redirect_to #match, notice: 'Match was successfully updated.' }
format.json { render :show, status: :ok, location: #match }
else
format.html { render :edit }
format.json { render json: #match.errors, status: :unprocessable_entity }
end
end
MatchPick.where(:matchID => params[:id]).update_all(result: match_params[:result], closed: match_params[:played], points: 0)
MatchPick.where(:matchID => params[:id], :userPick => match_params[:result]).update_all(points: 3)
update_user_points
end
def update_user_points
#users = User.all
#users.each do |user|
user.points = 4
puts params
end
end

You can't use update_all unless you're updating a field in all the records to the same value, which is not the case here.
How about this?
MatchPick.where(:matchID => params[:id], :userPick => match_params[:result]).each do |mp|
mp.user.update_attribute(:points, mp.user.points + 4)
end
(this is assuming that MatchPick is a join record between Match and User and has a belongs_to relationship with User)

Related

Editing Triple Nested Fields is Creating Duplicates Rails 5.1

I have a triple nested resource, which I am able to create new values for perfectly well. However when trying to edit the record, I am getting duplicated fields for the nested values, which is then creating multiple entries.
I am multiplying the nested fields by 3.
def new
#roast = Roast.new
3.times {#roast.countries.build.regions.build}
end
Edit method:
def edit
#roast = Roast.friendly.find(params[:id])
3.times {#roast.countries.build.regions.build}
end
Should I be removing the 'build' element here? I do want the user to be able to add new values if required however.
And create has nothing special for this:
def create
#roast = Roast.new(roast_params)
respond_to do |format|
if #roast.save
format.html { redirect_to #roast, notice: 'Roast was successfully created.' }
format.json { render :show, status: :created, location: #roast }
else
format.html { render :new }
format.json { render json: #roast.errors, status: :unprocessable_entity }
end
end
end
I obviously want the 3 nested fields to show on the edit page, but what am I doing wrong for it to keep repeating.
You don't need to add countries or regions in the edit. Just find the Roast.
#This is wrong
3.times {#roast.countries.build.regions.build}
When you edit a Roast, you can access its countries through #roast.countries
If you want, you can define an instance variable to use in the form (although not needed) #countries = #roast.countries

Rails: Understanding Query Model Syntax

I have my Ruby on Rails app up and running with 3 scaffolded models. So far so good. Now I'm coding business logic and get a syntax error and can't quite understand how to code a variable.
Details:
3 models: Document, Employee, and EmpDocument.
Business rule: Each time a new Document is added create an EmployeeDocument for each Employee
1.) Loop through Employees
2.) Cut an EmpDocument.rcd
I get an error on the .Create line, because I don't have my variables coded correctly.
I've looked through documentation without finding any rules/examples.
Document.Model
def create
#document = Document.new(document_params)
respond_to do |format|
if #document.save
format.html { redirect_to #document, notice: 'Document was successfully created.' }
format.json { render :show, status: :created, location: #document }
# create an EmpDocument record for each employee for this new document
##employees = Employee.find(:all)
Employee.all.each do |employee|
Empdocument.Create(:document_id => #document.document_id, :employee_id => employee.employee_id, :viewed => '0001-01-01')
end
else
format.html { render :new }
format.json { render json: #document.errors, status: :unprocessable_entity }
end
end
end
here's the error:
"undefined method `document_id' for #"
##employees = Employee.find(:all)
Employee.all.each do |employee|
Empdocument.Create(:document_id => #document.document_id, :employee_id => employee.employee_id, :viewed => '0001-01-01')
end
For your current requirement, I would encourage you to look into the after_create callback in ActiveModel.
What you can do then in your Document Model is
after_create :create_emp_documents
def create_emp_documents
Employeee.all.each do |employee|
self.empdocuments.create(employee_id: employee.id)
end
end

find results from table after update, where (attribute integer) is equal to the (primary id integer)

I am updating an object in a table with attributes : :primary_id, :zucode_number, :zucode_email
The updated row object does NOT have the attributes :zucode_number and :zucode_email .
Other different rows in the same table do have the attributes i need, :zucode_number and :zucode_email.
:zucode_number(integer) can be equal to, is sometimes equal to the :primary_key(integer)
How to get the rows where :zucode_number is equal to :primary_key and send email to :zucode_email on those rows.
Hope this makes sense...
Ive been, and i am, struggling with this, and can't get it to work. Thanks in advance for your help.
Asked another question similar yesterday but think it wasn't clearly explained.
I am updating (successfully) the object(zucode), sending it through a link to:
def changezu
zucode = Zucode.where( id: params[:id], secret2: params[:secret2] ).first
if zucode
respond_to do |format|
format.html { redirect_to edit_zucode_path, notice: 'Make changes!.' } #edit_zucode_path
format.json { head :no_content }
end
end
end
my update method is :
def update
respond_to do |format|
if #zucode.update(zucode_params)
format.html { redirect_to #zucode, notice: 'Zu was successfully updated.' }
format.json { render :show, status: :ok, location: #zucode }
else
format.html { render :edit }
format.json { render json: #zucode.errors, status: :unprocessable_entity }
end
end
end
UPDATE::
added to controller :.
after_action :trynew, only: [:update]
and
def trynew
#zucode = Zucode.where("zucode_number=id")
#ZuMailer.mymail.(zucode).deliver
end
with the mailer commented out, it does not give error but nothing happens. Looking into log the correct rows are not being selected or mentioned. I only see reference to the updated row. If i run with the mailer i get error for "wrong arguments 0 of 1"
As I can see, that you need to use callbacks of object lifecycyle.
I am assuming that you have a model called Zucode .
Inside that model add after_update method.
class Zucode
after_update :method_to_call
def method_to_call
zucodes = Zucode.where('zucode_number=id')
#perform action on zucodes
end
end
The method method_to_call will get called each time a Zucode is updated.

Rails 4 Passing existing/previous record values to new record

I'll try to explain this as thoroughly as possible. I'm trying to figure out what the best way of passing existing data that should not be tampered with as a hidden value through a form -- or if there is a better way to send data on rails to a new "create" method.
Basically what I'm trying to achieve is, first a transaction created and stores group_id, owner_id, user_id, message and status. Then when the user "accepts" the request, a new transaction is created with basically all the same information (group_id, owner_id, and user_id), except the status and message can be changed.
So here's how the flow goes:
A user first creates a request as such:
Request.create("gid" => 1, "user_id" => 2, "owner_id" => 4, "message" => "Bla Bla", "status" => 'pending')
Then the owner of that request views that request, and is able to accept or reject the transaction. Bare in mind, all the requests are in the same page, so there will be many accepts, and rejects on the same page, but each is iterated through the #request = Requests.where(:owner_id => 4).
The problem with hidden input is that you can tamper with it easily to change columns you aren't supposed to. What I'm trying to figure out is, if there is a way to pass the values into the accept method, with both new (message) and old (group_id, user_id, owner_id) to create a new row with?
The new transaction will basically be as such:
Request.accept("gid" => ori_trans, "user_id" => ori_trans, "owner_id" => ori_trans, "message" => "New Message", "appointment" => ori_trans, "status" => 'accepted')
def accept
#request = Request.new(request_params)
#request.status = 'accepted'
#request.expert_id = current_user.id
respond_to do |format|
if #request.save
format.html { redirect_to #request, notice: 'Request was successfully created.' }
format.json { render action: 'show', status: :created, location: #request }
else
format.html { render action: 'new' }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
def request_params
params.require(:request).permit(:gid, :user_id, :message)
end
Problem with whitelisting GID and user_id is that users can temper with forms to allow for this field to be changed. Ideally, I'd only want to permit :message to come through from the params.
Hope this explains what I'm trying to do - let me know if you have any suggestions.
I think the following code should do what you want:
def accept
original_request = Request.find(params[:request][:id])
if original_request.owner_id != current_user.id
#do something here, logout maybe?
return
end
#request = original_request.dup
#request.message = params[:request][:message]
#request.status = 'accepted'
respond_to do |format|
if #request.save
format.html { redirect_to #request, notice: 'Request was successfully created.' }
format.json { render action: 'show', status: :created, location: #request }
else
format.html { render action: 'new' }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
With this code, even if someone tampers with the request id parameter, if they try and accept a request they don't own, then it will fail.

Update if exists, else do nothing?

I'm trying to update a value of a model if and only if the model exists. If it doesn't, I do nothing. Searching only seems to return update or create questions/answers, but I do not want to create.
I know I can do it with a simple:
found = Model.find_by_id(id)
if found
update stuff
end
However, I feel like there is a way to do this in one call, without assigning any temporary local values or doing an if.
How would I write a rails call to update a record without noisy errors if it doesnt exist?
Latest Rails 3.x
You can use try method of Rails before calling update_attributes on result of find_by_id or where.
try will return nil silently without raising exception if the record does not exist. If the record exists, it will update it.
found = Model.find_by_id(id).try(:update_attributes, {key: value})
You can use first_or_initialize combined with new_record? as following:
client = Client.where(first_name: 'Nick').first_or_initialize(locked: false)
client.save unless client.new_record?
Assuming your model is called 'Event' and you search by id, you could do:
e = Event.where(:id => id)
if !e.empty?
e.first.value = new_value
e.first.save!
end
In Rails 4, this is probably the simplest solution I found:
# POST /users
# POST /users.json
def create
#user = User.find_or_initialize_by(fbid: user_params[:fbid])
#user.assign_attributes(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render action: 'show', status: :created, location: #user }
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
If the user with FBID exists, then the record will be updated; otherwise, a new one will be created. You can update the record to match whatever column you want to keep unique. Probably indexing the column would help the search & retrieval etc.
Hope this helps!

Resources