Compilation error: module Ecto.Model is not loaded and could not be found - phoenix-framework

Getting the issue on compilation, please have a look, may be anyone is familiar with the error
== Compilation error on file web/controllers/order_controller.ex ==
** (CompileError) web/controllers/order_controller.ex:2: module Ecto.Model is not loaded and could not be found
expanding macro: PhoenixCart.Web.__using__/1
web/controllers/order_controller.ex:2: PhoenixCart.OrderController (module)
(elixir) expanding macro: Kernel.use/2
web/controllers/order_controller.ex:2: PhoenixCart.OrderController (module)
Controller
defmodule PhoenixCart.OrderController do
use PhoenixCart.Web, :controller
alias PhoenixCart.Order
plug :scrub_params, "order" when action in [:create, :update]
def index(conn, _params) do
orders = Repo.all(Order)
render(conn, "index.html", orders: orders)
end
##<more code>
end
web.exs //controller part
def controller do
quote do
use Phoenix.Controller
# Alias the data repository and import query/model functions
alias PhoenixCart.Repo
import Ecto.Model
import Ecto.Query, only: [from: 2]
# Import URL helpers from the router
import PhoenixCart.Router.Helpers
end
end

Removed 'Model' in Ecto.Model, as use Ecto.Model has been deprecated and removed
Thank you #Dogbert, for help.

Related

Why elixir debugger is calling built-in function instead of mine if they have same name

Here is a simple module with 2 breakpoints in functions which are calling another functions with names exactly the same as built-in ones: get/1 and put/2
defmodule Test do
def call_put() do
require IEx; IEx.pry
put("k", "v")
end
def call_get() do
require IEx; IEx.pry
get("k")
end
def put(_k, _v)do
IO.puts("Doing put")
end
def get(_k) do
IO.puts("Doing get")
end
end
Executing it in a shell:
iex(1)> Test.call_get
Break reached: Test.call_get/0 (lib/test.ex:7)
5: end
6: def call_get() do
7: require IEx; IEx.pry
8: get("k")
9: end
pry(1)> get("a")
:undefined
pry(2)> Test.get("a")
Doing get
:ok
As it is visible, calling get/1 from debugger results in executing built-in get/1 and put/2 instead of function from my Test module.
To work it properly I need to namespace my function call. Could anyone explain me this behaviour?
What happening here is: the context differs. Look:
iex|1 ▶ defmodule Test do
...|1 ▶ def get(p), do: p
...|1 ▶ IO.inspect quote do: (def get(), do: get(42))
...|1 ▶ end
{:def, [context: Test, import: Kernel],
[{:get, [context: Test], []}, [do: {:get, [], '*'}]]}
The AST of get/0 function would include the context:
{:get, [context: Test], []}
This is how the compiler knows what to call for unqualified functions. Basically, the ability to call a function from within the same module unqualified is a syntactic sugar. While in a breakpoint, the module is already compiled and there is surely no access to “local” functions since there are no “local” functions anymore. You might import Test to gain an access to the functions by their unqualified names.

routing resources with a wild card

I have this routing
scope "/api", MosaicApi do
pipe_through :api
# resources "/cards", CardController, except: [:new, :edit]
resources "/estimates/:product", EstimateController, except: [:new, :edit]
Initially I used the generated CardController and things worked (at least POST/create did), but now I want to generalise as Card is a product type and I have a variety of other products that need to expose the exact same CRUD operations. So I am trying to morph Card* to Estimate*
In EstimateController I now have this
defmodule Api.CardController do
use Api.Web, :controller
alias Api.Card
def create(conn, %{"product" => product}) do
conn
|> render("result.json", product: product)
end
...
What I want to do is pattern match on product to bring into scope the relevant Struct (Card, ...), but I've got stuck as the code above yields this error
undefined function Api.EstimateController.init/1 (module Api.EstimateController is not available)
Api.EstimateController.init(:create)
I'm confused as init is not mentioned in http://www.phoenixframework.org/docs/controllers at all
Other indications that things are mostly good
mix phoenix.routes
page_path GET / Api.PageController :index
estimate_path GET /api/estimates/:product Api.EstimateController :index
estimate_path GET /api/estimates/:product/:id Api.EstimateController :show
estimate_path POST /api/estimates/:product Api.EstimateController :create
The function init/1 is defined in https://github.com/phoenixframework/phoenix/blob/v1.1.4/lib/phoenix/controller/pipeline.ex#L98
def init(action) when is_atom(action) do
action
end
It looks like you are not calling use Phoenix.Controller in your EstimatesController.
Usually this is done with:
use Api.Web, :controller

Phoenix framework router.ex config for JSON

I've installed phoenix JSON package through mix phoenix.gen.json V1.Post posts title:string content:string secret:string --no-model
but got this error:
== Compilation error on file web/controllers/v1/post_controller.ex ==
** (CompileError) web/controllers/v1/post_controller.ex:14: Shopper.V1.Post.__struct__/0 is undefined, cannot expand struct Shopper.V1.Post
(elixir) src/elixir_map.erl:55: :elixir_map.translate_struct/4
(stdlib) lists.erl:1353: :lists.mapfoldl/3
(elixir) src/elixir_clauses.erl:36: :elixir_clauses.clause/7
(elixir) src/elixir_def.erl:178: :elixir_def.translate_clause/7
(elixir) src/elixir_def.erl:167: :elixir_def.translate_definition/8
(elixir) src/elixir_def.erl:82: :elixir_def.store_definition/9
web/controllers/v1/post_controller.ex:13: (module)
(stdlib) erl_eval.erl:669: :erl_eval.do_apply/6
here is my router.ex code:
defmodule Shopper.Router do
use Shopper.Web, :router
pipeline :api do
plug :accepts, ["json"]
end
scope "/", Shopper do
pipe_through :api
resources "/v1/posts", V1.PostController
end
end
From the documentation said:
Add the resource to the proper scope in web/router.ex:
resources "/posts", PostController
But.. I can't make it work, could anybody help me? Thank you.
Please note that this is for phoenix 1.0 and elixir 1.0.
My question is pointing to wrong problem, but I'll keep it that way so it can help people who coming with similar conclusion.
The solution is to add a model for V1.Post but running mix phoenix.gen.model will give a compile error which already stated in my question. So, I must comment the offending code which is the entire def create(conn, %{"post" => post_params}) in V1.Post controller.
After that run mix phoenix.gen.model V1.Post posts name:string then uncomment the offending code.
To test, run mix phoenix.routes which in my case returning
Compiled web/models/v1/post.ex
Generated shopper app
page_path GET / Shopper.PageController :index
post_path GET /api/v1/posts Shopper.V1.PostController :index
post_path GET /api/v1/posts/:id Shopper.V1.PostController :show
post_path POST /api/v1/posts Shopper.V1.PostController :create
post_path PATCH /api/v1/posts/:id Shopper.V1.PostController :update
PUT /api/v1/posts/:id Shopper.V1.PostController :update
post_path DELETE /api/v1/posts/:id Shopper.V1.PostController :delete
Success!

Padrino cannot use output helpers in custom form builder

I am trying to create a custom form builder that generates a span with an error message. I keep getting the message
NoMethodError at /class/create
undefined method `content_tag' for #<Padrino::Helpers::FormBuilder::StandardFormBuilder:0x00000005aa24b8>
Here is my extension:
module Padrino
module Helpers
module FormBuilder
class CustomFormBuilder < AbstractFormBuilder
def errors_for(field)
if object.errors[field.to_sym]
error = object.errors[field.to_sym].first
content_tag(:span, error, class: 'error')
end
end
end
end
end
end
end
I have placed this extension in the lib folder.
You should include helper modules you need in your builder class.
module Padrino
module Helpers
module FormBuilder
class CustomFormBuilder < AbstractFormBuilder
include TagHelpers
include FormHelpers
include AssetTagHelpers
include OutputHelpers
...your methods here...
end
end
end
end

Monkey patch class methods

I'm trying to do some monkey patching in ActiveShipping UPS class .
I need to add a class level method (starting with .self), so here it's what I'm trying to do:
module ActiveMerchant
module Shipping
class UPS < Carrier
def self.process_request(receiver, sender, packages, options = {})
# some code
end
def regular_method
"foobar"
end
end
end
end
Unfortunately when I'm trying to use it:
ActiveMerchant::Shipping::UPS.process_request(receiver etc)
I get an error:
NoMethodError: undefined method `process_request' for ActiveMerchant::Shipping::UPS:Class
from (irb):6
from C:/Ruby19/bin/irb.bat:19:in `<main>'
There is no class method named process_request in original class.
In original UPS class provided in gem there is one static method defined self.retry_safe = true
and I can use it without errors.
I can also use regular_method after creating instance of UPS class.
More details provided:
I'm working with Rails 2.3 ( :-( ) and Ruby 1.9.2. I have no influce on environment.
Monkey patched code is under plugins/my_plugin/lib/active_shipping/ext/carriers/ups.rb
In /active_shipping I have file named extensions.rb in which i have:
require 'active_shipping'
require_relative 'ext/carriers'
require_relative 'ext/carriers/ups'
It deals with loading everything properly (I suppose basing on regular_method beheaviour from first chunk of code in my question).
I try to invoke process_request in one of my Controllers. This part is little tricky, beacuse i'm using sth like this:
MyModel.courier_service.process_request(parameters)
where courier_service, in this case holds the ActiveMerchant::Shipping::UPS class.
I'm still a newbie in Ruby and don't know what sort of details i should provide.
Maybe you want to do it in another way
File patch_classes.rb:
module ActiveMerchantExpand
module Shipping
module ClassMethods
def self.process_request(receiver, sender, packages, options = {})
# some code
end
end
module InstanceMethods
def regular_method
"foobar"
end
end
def self.included(receiver)
receiver.extend ClassMethods
receiver.send :include, InstanceMethods
end
end
end
Then you have to load your class "ActiveMerchant::Shipping::UPS"
and after that you can attach your methods to your class via
Rails.configuration.to_prepare do
require_dependency [[file for ActiveMerchant::Shipping::UPS]]
require 'patch_classes' )
ActiveMerchant::Shipping::UPS.send(:include, ::ActiveMerchantExpand::Shipping)
end
This is from rails plugin writing, i hope this helps.
regards tingel2k
Do you explicitly require file with your monkey patch? If you just put it under your app or lib path without requiring, it wouldn't load because constant ActiveMerchant::Shipping::UPS is defined in gem and it doesn't trigger dependency resolution mechanism.

Resources