I'm trying to collect all the clients of my current group_id in json (/groups/1/clients.json)
I'm using a custom method because I want all the groups of the current_user aswell.
Anyway; I have a method that checks in a loop of all the groups of current_user if the params[:group_id] equals the group.id of my loop. And if it is; Output my clients in a JSON file.
Now I'm 100% positive that params[:group_id] and group.id exist(I've both been able to output them into the JSON if I escape the if params[:group_id] == group.id.
Nonetheless, when I'm using the IF statement I don't get the output I need. Does anyone have any clue why my IF statement doesn't go as I was expecting?
#usersGroups = current_user.groups
if params[:group_id]
#usersGroups.each do |group|
if group.id == params[:group_id]
respond_to do |format|
format.json { render json: group.clients, status: :unprocessable_entity }
end
end
end
end
group.id.to_s == params[:group_id]
Also you can clean up your code like this:
group = Group.where(user_id: current_user.id).find(params[:group_id])
respond_to do |format|
format.json { render json: group.clients, status: :unprocessable_entity }
end
Related
There are multiple answers that explain how you can have nested resources, however, my use case is a bit different.
Batches belong to orders and an order has many batches.
I can understand how it works if you have a form for an order and can create batches within that form, but cannot comprehend a good way for my situation.
I have a form for a nested resource (batch) where the parent (order) may or may not exist. They may select whether or not it exists via radio buttons. If it exists, they then just simply select which order it belongs to .. simple. If it doesn't exist, I show fields for the order and submit order params alongside of batch params. I want to make sure to rollback the order creation if the batch does not save.
Here is the code I have thus far.
def create
#batch = Batch.new(batch_params)
Batch.transaction do
if params[:new_order] == "newOrder"
#order = Order.new(order_params)
#order.project_id = params[:batch][:project_id]
begin
#order.save!
rescue
respond_to do |format|
format.html { render action: 'new' }
format.json { render json: {order: #order.errors}, status: :unprocessable_entity }
format.js { render json: {order: #order.errors}, status: :unprocessable_entity }
end
raise ActiveRecord::Rollback
return
end
##batch.order_id = #order.id
end
respond_to do |format|
begin
#batch.save!
format.html { redirect_to #batch, notice: 'Batch was successfully created.' }
format.json { render json: #batch }
format.js { render json: #batch }
rescue
binding.pry
raise ActiveRecord.Rollback
format.html { render action: 'new' }
format.json { render json: {batch: #batch.errors}, status: :unprocessable_entity }
format.js { render json: {batch: #batch.errors}, status: :unprocessable_entity }
end
end
end
end
This isn't behaving quite like I want it and seems quite ugly. I have a feeling I'm making it more difficult than I need to. What's the best approach in a situation like this? Much appreciated!
It seems like this is a great opportunity to use a Service Object: https://www.engineyard.com/blog/keeping-your-rails-controllers-dry-with-services .
This pattern is very useful for keeping Model and Controllers clean, and making sure those parts of the application are keeping to the Single Responsibility Principle.
What I would do in this case is create a service class called CreateBatch that takes in the parameters and performs the correct logic for each case. You can then render the correct output in the controller. This will also help clean up the conditionals and early returns you have.
For example:
# app/controllers/batches_controller.rb
def create
project_id = params[:batch][:project_id]
new_order = params[:new_order]
result = CreateBatch.new(new_order, batch_params, order_params, project_id).call
if result.errors
# handle errors with correct format
else
# handle successful response with correct format
end
end
# app/services/create_batch.rb
class CreateBatch
def initialize(new_order, batch_params, order_params, project_id)
#new_order = new_order
#batch_params = batch_params
#order_params = order_params
#project_id = project_id
end
def call
if new_order?
create_new_order
else
add_batch_to_existing_order
end
end
private
def new_order?
#new_order
end
def create_new_order
order_params = #order_params.merge(project_id: #project_id)
Order.save(order_params)
end
def add_batch_to_existing_order
Batch.create(#batch_params)
end
end
I did not run this so it may take a bit of tweaking to work, however, I hope it's a good starting point. One of the awesome things about this refactor is you now have 1 conditional for the logic and 1 conditional for the response, no need for adding in Transaction blocks, and no early returns. It may make sense to break the call method into 2 different methods that you can call from the controller. Using service classes like this makes the code much easier to unit test as well.
Why not move error handling and response rendering outside of the transaction?
def create
#batch = Batch.new(batch_params)
Batch.transaction do
if params[:new_order] == "newOrder"
#order = Order.new(order_params)
#order.project_id = params[:batch][:project_id]
#order.save!
#batch.order_id = #order.id
#batch.save!
end
end
respond_to do |format|
format.html { redirect_to #batch, notice: 'Batch was successfully created.' }
format.json { render json: #batch }
format.js { render json: #batch }
end
rescue StandardError => error
#error = error
format.html { render action: 'new' }
format.json { render json: {error: #error, batch: #batch.errors}, status: :unprocessable_entity }
format.js { render json: {error: #error, batch: #batch.errors}, status: :unprocessable_entity }
end
It's still quite complex, but it's definitely more readable. The next step would be to extract the whole transaction block to a service.
I looked at a few different answers similar to this question, but they all are getting the id passed into the params hash, it is just coming back as a nil value. I cant seem to get the id to be whitelisted and I cant figure out why.
This is my create and show action, also includes the params. I explicitly whitelisted id although I dont know if it is necessary.
def show
#board = Board.find(params[:id])
end
def create
#board = Board.new(board_params)
if #board.save
# flash[:notice] = 'You successfully created your post!'
redirect_to board_path
else
render 'new'
# flash[:danger] = 'One or more errors occurred when processing your post'
end
end
private
def board_params
# params.require(:board).permit!
params.require(:board).permit(:id, :project_name, :project_description, :postition_title, :project_url, :project_headquarters, :application_process)
end
The output of my routes show action
board GET /boards/:id(.:format) boards#show
And the output of the params hash on board#create
Parameters: {"utf8"=>"✓", "authenticity_token"=>"k+KKRhBk4Dnba1vxtFCanI2grfhNXFSgJpfEBLnhPdablfOsXRi1wBehPpM1qgx1pySrqxVHTeiwkneluXwRIQ==", "board"=>{"project_name"=>"sdf", "postition_title"=>"sdf", "project_headquarters"=>"sdf", "project_url"=>"fsd", "project_description"=>"dfs", "application_process"=>"dfs"}, "commit"=>"Create Board"}
Can anyone see what I need to change in order to get the id passed in correctly?
Try this.
Take :id out of params.
def show
end
def create
#board = Board.new(board_params)
respond_to do |format|
if #board.save
format.html { redirect_to #board, notice: 'Board was successfully created.' }
format.json { render :show, status: :created, location: #board }
else
format.html { render :new }
format.json { render json: #board.errors, status: :unprocessable_entity }
end
end
end
in create action...
change ..
redirect_to board_path
to...
redirect_to board_path(#board)
###OR
### this calls the show action
redirect_to #board
I am totally new in ruby. My Ruby version 2.2. I have an edit profile form. I want to show both the table and form data in two different different place. Please check my code
users_controller.rb
def edit_profile
#user = User.get_profile(session[:user_id])
raise $user.inspect
respond_to do |format|
if params[:user][:avatar]
params[:user][:photo] = orginal_file_upload params[:user][:avatar]
end
raise params.inspect
if #user.update(user_params)
format.html { redirect_to :back, notice: 'Your profile was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :my_profile }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
Here I have define raise $user.inspect and raise params.inspect I want to get both data. But here in my page only coming first one. Please check and let me know how to get my both array value.
Thank you.
raise is a mechanism of throwing errors. raise $user.to_s returns the control out of action. You can use puts method to display the values in controller.
The correct code will be:
def edit_profile
#user = User.get_profile(session[:user_id])
respond_to do |format|
if params[:user][:avatar]
params[:user][:photo] = orginal_file_upload params[:user][:avatar]
end
#user.update(user_params)
format.html { render :inline => "User<p> ID:<%= #user.id %><br>NAME: <%= #user.name %><br>EMAIL: <%= #user.email %></p>Params <p><%= params.inspect%></p>".html_safe }
end
end
Assign them to instance variables like #user and #params and access them in your views. Having said that you already have assigned #user variable and params is accessible in your views automatically.
# In your view
<%= #user.name %>
<%= params %>
Also, consider making your controller RESTful. You can send PUT request to your controllers URL (eg. PUT profile/1) it will automatically call your ProfileController#edit method.
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.
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)