Cannot get Bubblewrap data from model to controller - rubymotion

I am building an iOS app using the latest version of Rubymotion.
I got a tableview that I would like to fill with data from a remote API.
I named the controller: ProjectsController
I named the model: Project
In the controller viewDidLoad I want to get a list of projects from the API.
I have created a static method in the Project model called load_projects.
def self.load_projects
BW::HTTP.get("#{URL}projects?id=25&project_id=24&access_token=#{TOKEN}") do |response|
result_data = BW::JSON.parse(response.body)
output = result_data["projects"]
output
end
end
This is my viewDidLoad in the controller:
def viewDidLoad
super
#projects = Project.load_projects
self.navigationItem.title = "Projekt"
end
I do not get the same response in the viewDidLoad as I do in the model. In the model method I get the correct response data but in the viewDidLoad I get a "meta" object returned. A BubbleWrap::HTTP::Query object. What am I doing wrong?
Update one
I tried to use the first answer below like this but I get an error:
def tableView(tableView, cellForRowAtIndexPath:indexPath)
cellIdentifier = self.class.name
cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) || begin
cell = UITableViewCell.alloc.initWithStyle(UITableViewCellStyleDefault, reuseIdentifier:cellIdentifier)
cell
end
project = #projects[indexPath.row]['project']['title']
cell.textLabel.text = project
cell
end
The error is:
projects_controller.rb:32:in `tableView:cellForRowAtIndexPath:': undefined method `[]' for nil:NilClass (NoMethodError)
2012-11-09 01:08:16.913 companyapp[44165:f803] *** Terminating app due to uncaught exception 'NoMethodError', reason: 'projects_controller.rb:32:in `tableView:cellForRowAtIndexPath:': undefined method `[]' for nil:NilClass (NoMethodError)
I can show the returned data here without errors:
def load_data(data)
#projects ||= data
p #projects[0]['project']['title']
end

Ha, I just went through the exact same problem.
The solution I got was the following:
The BW::HTTP method is asynchronous, so your self.load_projects method will return a request object, instead of the JSON data that you want.
Essentially the BW:HTTP.get completes execution immediately and the self.load_projects method returns the incorrect data.
The solution that was suggested to me is the following:
Change your load_projects method so it accepts a view controller delegate:
def self.load_projects(delegate)
BW::HTTP.get("#{URL}projects?id=25&project_id=24&access_token=#{TOKEN}") do |response|
result_data = BW::JSON.parse(response.body)
delegate.load_data(result_data)
delegate.view.reloadData
end
end
Don't forget to reload your data, if you are importing into a table view controller.
Notice that the delegate is calling a load_data method, so make sure your view controller implements that:
class ProjectsController < UIViewController
#...
Projects.load_projects(self)
#...
def load_data(data)
#projects ||= data
end
#...
end
Then do whatever you want with #projects

Related

Pass locals from controller to active model serializer

I am trying to pass locals(prod: #product.id) to AMS in my controller, as follows:
#options_json = ActiveModel::SerializableResource.new(#option_types, prod: #product.id)
#options_json = #options_json.to_json(serialization_context: ActiveModelSerializers::SerializationContext.new(request), serialization_options: {prod: #product.id})
I am not sure whether to pass it during initialization or during call to to_json. Moreover I am unable to read this passed param in my OptionTypeSerializer. I've tried using options[:prod], serialization_options[:prod], serialization_opts[:prod] and a few different solutions that I found on stackoverflow, but none worked.
My AMS is pointed to master and in my gemfile.lock AMS version is active_model_serializers (0.10.0.rc5)
Also tried using:
#options_json = ActiveModel::SerializableResource.new(#option_types, serialization_context: ActiveModelSerializers::SerializationContext.new(request), prod: #product.id).to_json
but getting the value of instance_options[:prod] as null, although it is not null
Whenever I need to pass options into a serializer I do something like this:
# Controller
class CatalogPagesController < ApplicationController
# GET /catalog_pages/event/:id
def event
#catalog_pages = #event.catalog_pages
render json: #catalog_pages, index: true, each_serializer: Adm::CatalogPageSerializer
end
end
# Serializer
class CatalogPageSerializer < Adm::FormSerializer
attributes :id, :body, :catalog_page_templates
def include_catalog_page_templates?
return true unless #options[:index].present?
end
end
In this example I want to conditionally not return certain elements of JSON when coming from the index route.

My rails console shows the same model twice - uninitialized constant error

I have a model named pictures.rb aka Picture class which should map to pictures table but in rails console it gets displayed twice?
irb(main):013:0> #models = ActiveRecord::Base.subclasses.collect { |type| type.name }.sort
=> ["Picture", "Picture"]
I am trying to use Picture class aka picture.rb model in my ControlPanelController index function
so when I load my index page I get the following error
uninitialized constant ControlPanelController::Picture
def index
#pictures = Picture.all
end
I am guessing it might be because that Picture model shows up twice in rails console? Not sure.
The reason it can't find it is your model file name is called pictures.rb.
The filename should be picture.rb (not plural).
It should be:
app/models/picture.rb:
class Picture< ActiveRecord::Base
...
end

How to implement DelayedJob custom job for Prawn PDF rendering?

Im trying to use DelayedJob to render Prawn PDFs. Following the custom job code in the docs, I've come up with this:
/lib/jobs/pdf_handling.rb
RenderPdf = Struct.new( :id, :view_context ) do
def perform
user = User(id)
pdf = UserFolder.new( id, view_context )
name = "user_folder_report.pdf"
send_data pdf.render, filename: name, type: "application/pdf"
end
end
PagesController.rb
def user_folder
respond_to do |format|
format.pdf do
Delayed::Job.enqueue RenderPdf.new(#user, view_context)
end
end
end
this results in the error:
uninitialized constant PagesController::RenderPdf
Adding required RenderPdf at the top of the PagesController doesn't help.
What am I missing? How can I implement this so PDF generation occurs via DelayedJob? Thanks.
updates
When /jobs is moved under /apps the error changes to:
can't dump anonymous module: #<Module:0x007fca7a3ae638>
/application.rb
config.autoload_paths += Dir["#{config.root}/lib/assets/"]
updates
I changed
class RenderFolder < Struct.new( :type, :rating_id, :dis, :view_context )
def perform
to
class RenderFolder < ActiveJob::Base
def perform(...)
Then, using ActiveJob, you can do
RenderFolder.perform_later(...)
This seems to be working...Im still implementing.
the lib folder is no longer loaded by default in rails. you can either add it to the autoload_path or (what i would do) just have it in some app/xxx folder. typically, i have app/support or something for arbitrary utility classes.

Virtual attributes in Rails 4 from Rails 3

I am creating a Rails 4.10 app and I am using code from my Rails 3.2 app.
In this app I got a form where I add a virtual attribute called group_ids and then use after_save to add groups to a user.
In my 3.2 code:
attr_accessor :group_ids
after_save :add_groups
def add_groups
if group_ids.present?
self.assignments.user_groups.delete_all
group_ids.reject!(&:empty?)
group_ids.each do |group|
assignment = Assignment.new
assignment.assignable_id = group
assignment.assignable_type = "UserGroup"
assignment.backend_user_id = self.id
self.assignments << assignment
end
end
end
In my 4.10 code:
Controller:
params.require(:backend_user).permit(:firstname, :lastname, :group_ids)
How can I use the Add_groups method in 4.10?
Looking at your code, it seems that group_ids are not being whitelisted correctly in the controller code resulting in group_ids not being set which in turn would result in group_ids.present? condition returning false in your after_save callback. So, none of the statements gets executed in the callback.
To cut it short, after_save callback add_groups is getting executed but its not doing anything.
To resolve this, you should be whitelisting group_ids as an Array in your controller code:
params.require(:backend_user).permit(:firstname, :lastname, :group_ids => [])

setting up controller for test

i'm trying to write a functional test for my controller in rubymotion using bacon.
in my controller i have some code that populates some data:
def viewWillAppear(animated)
song_text.text = chant.song_text
...
end
i am setting the chant variable when i push that controller to the navigation-controller.
this works fine in the app, but when i try to do that in a before-block of the spec it does not work, because viewWillAppear gets called before the block and it fails with a NoMethodError: undefined method 'song_text' for nil:NilClass.
is there some way to handle this situation? is there some other way to populate the data or use a different method than viewWillAppear?
I've experience a similar issue that was solved by calling the super method in the viewWillAppear method
The RubyMotion support answered my support ticket indicating, that this is the expected behavior of controllers in bacon.
I worked around the whole thing by stubbing my class under test in the bacon spec like so:
# spec/chant_controller_spec.rb
class ChantControllerStub < ChantController
def chant
#chant ||= create_chant
end
end
describe "ChantController" do
tests ChantControllerStub
it "displays a chant" do
view('verse').should.not == nil
end
end