Can't delete a embedded element with Mongoid - ruby-on-rails

Still working on my Rails/MongoDB app, I have yet another problem.
This time, I can create embedded documents, but can't delete them, though I've been doing what has been said in another Stackoverflow topic (http://stackoverflow.com/questions/3693842/remove-an-embedded-document-in-mongoid)
Here goes my controller :
class FeedSubscribtionsController < ApplicationController
has_to_be_connected
def create
if session[:user_id] != params[:id]
#self = current_user
attributes = { :user => #self, :userId => params[:id], :feedId => params[:feed] }
subscribtion = FeedSubscribtion.create attributes
success = subscribtion.save
render json: { :success => success, :feed => params[:feed] }
end
end
def destroy
success = false
if session[:user_id] != params[:id]
#self = current_user
uid, fid = params[:id], params[:feed]
#feed = #self.feed_subscribtions.where :userId => uid, :feedId => fid
if #feed.count > 0
#self.feed_subscribtions.delete #feed.first.id.to_s
success = #feed.first.save
end
end
render json: { :success => success, :feed => params[:feed] }
end
end
The weirdest part is that everything seems to go well : success is equal to true in the rendered JSON object.
I also tried to replace "success = #feed.first.save" with "#self.save" : in that case, it returns false, but with no further explanations.
(I do know that for the logic behind this controller to be perfect, I should loop on the #feed array, and I will once it starts working ^^ it's just easier to debug that way)
So, is there any way I may find out why #ßelf.save fails, or why #feed.first.save doesn't fail but doesn't actually save either ?
Thanks.

Here is what you're doing as I see it
You are using FeedSubscriptionsController to delete the object with id if #feed.first, then you try and save #feed.first, but #feed.first points to an already deleted object, so it's failing to save it.

Related

Rails API Does not split Json

Weird problem. If the class at the bottom was a module, split the Json without problems, if it was only methods, also works, but the problem is.. when it is a class, it does not split the Json anymore, and returns an empty array.. however, if being a class, I do a puts the object, it actually puts it..
Any thoughts about why? How can I fix it?
I have this controller:
def index
begin
call_employee_work_locations_api
rescue => ex
render :json => {"service unavailable": "0001" }, :status => :service_unavailable
end
end
I have this service:
def call_employee_work_locations_api
auth = {:username=>ENV["USERNAME"], :password=>ENV["PASSWORD"]}
employee_locations = HTTParty.get(employee_work_Location_url , :basic_auth => auth)
#serialize_work_location(employee_locations)
serializer = EmployeeSerializer.new
serializer.serialize_work_location(employee_locations)
end
I have this builder:
json.array!(#top_locations) do |location|
json.extract! location, :name, :description, :latitude, :longitude
end
I have this class:
class EmployeeSerializer
def serialize_work_location(employee_locations)
employee_locations= JSON.parse(employee_locations)
locations=[]
employee_locations["work_locations"].each do |attributes|
location = Location.new(attributes["latitude"],attributes["longitude"],attributes["description"],attributes["name"])
locations.push(location)
end
employee_locations_selector(locations)
end
def top_office_location_selector(locations, city)
top_locations=[]
locations.each do |office|
if office.name == city[0] then top_locations.push(office) end
if office.name == city[1] then top_locations.push(office) end
end
#top_locations = top_locations
p #top_locations <--- it prints the object perfectly, but does not pass to the view, I get an empty array instead.
end
def employee_locations_selector(locations)
city = locations.each_with_object(Hash.new(0)) { |locations, counts| counts[locations.name] += 1 }.max_by{|k,v| v}
top_office_location_selector(locations, city)
end
end
The instance variable #top_locations is being set within the scope of the EmployeeSerializer class, not your controller. As such it's just a normal instance variable and so Rails knows nothing about it. You can assign the return value of #top_office_location_selector to an instance variable in the controller and it should work.
On a side note, the code would be cleaned up a lot by using #map over #each.

Ruby on Rails - If statement using params - returning wrong result

I'm having a hard time getting something which should be incredibly simple to work.
I've got an online quiz with multiple choice questions and a pass/fail mark. I've got everything working correctly bar the damned emailer function at the end. No matter whether passed is set to true or false it's always sending out the passed email. Have I done something a bit daft in this code which I just can't see or am I going to have to go back through everything with a fine-tooth comb?
def finalize
quiztype = params[:quiztype]
slug = params[:slug]
#qd = Quizdata.where(quiztype: quiztype, usertoken: slug).take
if #qd
#qd.completed = true
quizdata = JSON.parse(#qd.quizdata)
quizdata["completed"] = true
#qd.quizdata = quizdata.to_json
#qd.passed = params[:passed]
if #qd.save
if params[:passed]
QuizMailer.results_email_user(quizdata, #qd).deliver
else
QuizMailer.results_email_user_failed(quizdata, #qd).deliver
end
QuizMailer.results_email_client(quizdata, #qd).deliver
render json: { errors: [] }
else
render :json => { :errors => #qd.errors.full_messages }, :status => 422 #Unprocessable entity
end
else
render :json => { :errors => [ "Record not found" ] }, :status => 404
end
end
Here you go:
Replace
if params[:passed]
with
if ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(params[:passed])
It was failing because, you are getting result in String format (not nil, which makes it return true always), instead of Boolean.
Hope it helps!
Parameters are passed as strings.
Should have been:
if params[:passed] == "true"
QuizMailer.results_email_user(quizdata, #qd).deliver
else
QuizMailer.results_email_user_failed(quizdata, #qd).deliver
end

Update value with first_or_create in rails

I have a table 'Likes' with columns business_id, user_id and liked(0,1) and a function 'change_like_status'.
Now on every function call, If the value is 1 then set it to 0 (or vice versa) and if record doesn't exists then create one with value 1.
The first_or_create method is working just fine but how can i toggle value of column 'liked' while using this method?
Here is my function:
def change_like_status
if current_user.present?
status = Like.where("business_id = ? AND user_id = ?",params['id'],current_user.id).first_or_create(:business_id => params['id'],:user_id => current_user.id,:liked => '1')
abort status.inspect
else
return render :json => {:status => false,:msg=>"You need to sign in before performing this action."}
end
end
In you controller, make the changes
def change_like_status
if current_user
status = Like.create_or_change_status(params[:id], current_user.id)
else
return render json: { status: false, msg: "You need to sign in before performing this action." }
end
end
In your model like.rb file, add a method
def self.create_or_change_status(business_id, user_id)
status = where(business_id: business_id, user_id: user_id).first
if status.nil?
status = create({business_id: business_id, user_id: user_id, liked: 1})
else
status.update_attributes(liked: !status.liked)
end
status
end
def change_like_status
if current_user
current_user.likes.find_by(business_id: params[:id]).switch_status!
else
return render json: { status: false, msg: "You need to sign in before performing this action." }
end
end
class Like
def switch_status!
self.update_column :liked, !liked
end
end
other approach should be something like that
class Like
def switch_status!
self.update_column :liked, !liked
end
end
class User
def likes id
likes_for_business id
end
def likes_for_business(id)
likes.find_by(business_id: id) || likes.create(:business_id: id, liked: true)
end
end
# controller
current_user.likes(params[:id]).switch_status!

Figuring out the plan to write an RSpec test

I have a controller as following:
class ReportsController < ApplicationController
respond_to :html
def show
client = ReportServices::Client.new(ServiceConfig['reports_service_uri'])
#report = client.population_management(params[:id])
if #report
#kpis = #report[:key_performance_indicators]
#populations = #report[:population_scores]
#population_summaries = #report[:population_summaries]
#providers = #report[:provider_networks]
end
respond_with (#report)
end
end
Which I want to write a RSpec test for it but have no clue where to start from, I guess because it has that URL in it, it makes it harder for me, I am pretty new to Rails and RSpec and have some basic knowledge of writing RSpec for my Models but this one has puzzled me for the whole weekend.
So the first thing to tackle is mocking the external API request. The general idea here is that your going to return a mock object from new that will respond to population_management and return what you expect for #report.
describe ReportsController do
before do
#report_data = {
:key_performance_indicators => 'value',
:population_scores => 'value',
:population_summaries => 'value',
:provider_networks => 'value'
}
# This will fake the call to new, return a mock object that when
# population_management is called will return the hash above.
#fake_client = double(:population_management => #report_data)
ReportServices::Client.stub(:new => #fake_client)
end
describe '#show' do
it 'assigns #report' do
get :show, id: 1
assigns(:report).should == #report
end
it 'assigns some shortcut vars' do
[:kpis, :populations, :population_summaries, :providers].each do |var|
assigns(var).should_not be_nil
end
end
# and whatever else you'd like
end
end
You can stub the client interface to write an isolated test of your controller.
describe RerpotsController do
it "assigns a new report as #report" do
expected_id = '1234'
expected_kpi = 'kpi'
report = { key_performance_indicators: expected_kpi, ... }
client = double(ReportServices::Client)
client.should_receive(:population_management).with(expected_id) { report }
ReportServices::Client.should_receive(:new) { client }
get :show, id: expected_id
assigns(:kpis).should eq(expected_kpi)
# ...
end
end
You probably don't need to unpack the report in the controller.

How can I include a model association in a JSON response in Rails?

I've looked at similar posts but can't seem to quite figure it out.
I have the following function which works just fine. The Listing model has a foreign key called price_id which maps to the Price model and its price_range column. Price_id is returned as part of the message object in the JSON response.
How can I return the corresponding price_range value from the association instead of the price_id value (as part of the message obj, and keep the other attributes)?
def update
#listing = Listing.find(params[:listing][:id])
#if params were passed in for updating
if #listing.update_attributes(params[:listing])
#should we return the whole thing or just what's needed?
json_response = {
"success" => #listing.save, #save to DB and assign true/false based on success...
"message" => #listing.attributes #USE attributes to show output the content of the #message obj, and not another object called "message"
}
respond_to do |format|
#json response
format.html { render:json => json_response }
format.xml { render :xml => #listing }
#normal response. Consider leaving this for now?
#format.html { render :action => "detail" } #refresh this page, with new data in it. Consider trying to use redirect instead?
#format.xml { head :ok }
end
end #end if
end
add a method in your Listing model with the price_range and call it in serializable_hash
class Listing
def price_range
price.price_range
end
end
Like explain on comment you can use delegate instead this method :
class Listing
delegate :prince_range, :to => price
end
In you controller you can now do :
json_response = {
"success" => #listing.save, #save to DB and assign true/false based on success...
"message" => #listing.serializable_hash(:methods => [:price_range])
}
Based on what I read in this article, you should be able to do this:
class Listing
def as_json
super(:include => :price)
end
end
Then in your controller:
json_response = {
"success" => #listing.save,
"message" => #listing.as_json
}
If I understand correctly, you want to add #listing.price.price_range value to the "message" ?
If so, try this:
"message" => #listing.attributes[:price_range] = #listing.price.price_range

Resources