I have a very simple model using Mongoid. I've added the use of Redcarpet to parse the MD and store it. However during update_attributes it is throwing an exception. Running the model and running the update through rails c works fine.
class Post
include Mongoid::Document
field :contents_markdown
field :contents
key :title
before_create :markdown
before_save :markdown
protected
def markdown
if self.contents_markdown
self.contents = Redcarpet.new(self.contents_markdown).to_html.html_safe
end
end
end
Here is the controller that blows up.
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { head :ok }
else
format.html { render action: "edit" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
Here is the exception and stacktrace. The line numbers will be slightly off as I have removed stuff from the model.
uninitialized constant Post::Redcarpet
app/models/post.rb:20:in `markdown'
app/controllers/posts_controller.rb:62:in `block in update'
app/controllers/posts_controller.rb:61:in `update'
If it matters, I'm running MRI 1.9.2-p290 and Rails 3.1-rc5.
Edit -
This all works fine when running tests and running through the console. However going through the controller to update/create the model seems to always fail. Additionally from the stacktrace, you can see the model is in the standard location.
You might be missing a require or a gem declaration depending on how you're using Redcarpet.
The Rails auto-loader will generally catch these if that is defined in a standard location like app/models or, as is optional, lib/.
Usually you can fix this by putting the appropriate require statement in a config/initializers/redcarpet.rb type file, or altering your Gemspec as necessary.
You can try changing Redcarpet.newto ::Redcarpet.new which will tell Ruby to look for a top-level constant Redcarpet. I think that will likely fix it, but it's possible that the problem is something more complex.
Related
LoadError in CandidatesController#create
Unable to autoload constant Usermailer, expected Z:/railsassignment/student/app/mailers/usermailer.rb to define it
When I submit a form I get the error above. The form processes a record and the candidate is added to the database however the welcome email I'm trying to send to the newly registered candidate doesn't send, and the error above prevents the user from proceeding.
Candidates Controller
def create
#candidate = Candidate.new(candidate_params)
respond_to do |format|
if #candidate.save
Usermailer.welcome(#candidate).deliver_now ***<-- Error highlights this line***
format.html { redirect_to #candidate, notice: 'User was successfully
created.' }
format.json { render :show, status: :created, location: #candidate }
else
format.html { render :new }
format.json { render json: #candidate.errors, status:
:unprocessable_entity }
end
end
end
usermailer.rb
Z:/railsassignment/student/app/mailers/usermailer.rb (usermailer directory)
class UserMailer < ActionMailer::Base
default from: "from#example.com"
def welcome(candidate)
#candidate = candidate
mail(:to => candidate.can_email, :subject => "Welcome to EmployeMe.com, You
have registered successfully!")
end
end
Should you need to see any more of the files drop me a comment and I'll be quick to add them to the question.
It seems like a case of messed up naming convention.
As per Rails naming convention, file names should be in snake_case and class names in CamelCase. In your scenario, the file name should be user_mailer.rb.
So either rename usermailer.rb to user_mailer.rb
or
class name UserMailer to Usermailer.
Always use snake case for your file names.
Z:/railsassignment/student/app/mailers/user_mailer.rb
NOT:
Z:/railsassignment/student/app/mailers/usermailer.rb
Always use camel case for your class names
UserMailer.welcome(#candidate).deliver_now
NOT:
Usermailer.welcome(#candidate).deliver_now
If your interested in how constants loading works with rails you could take a gander at this.
I am writing my first controller tests for Rails in Rspec. In testing the create action, I want to write a test that verifies that the 'new' template is rendered when the form is submitted with invalid attributes. In this case, that means a field is left blank.
I have found several examples that I have tried to follow verbatim. However, when using Rspec to trigger the create action, it seems like ActiveRecord actually tries to create that record which, due to validations, fails. Thus, my test fails before I even get to test the redirect function. This does not seem to be an issue for the people writing the tutorials or StackOverflow answers.
What is the best way to test the create action in a controller, given invalid attributes?
Rails 4.0.0, Ruby 2.0.0, Rspec 3.0.0.beta2
order_items_controller_spec
describe "POST create" do
context "with invalid attributes" do
it "re-renders the new method" do
post :create, order_item: FactoryGirl.attributes_for(:order_item, :buyer_id => nil)
expect( response ).to render_template :new
end
end
end
order_items_controller
def create
#order_item = OrderItem.new(order_item_params)
respond_to do |format|
if #order_item.save!
format.html { redirect_to cart_path(#order_item), notice: 'Your trip has been added to your cart.' }
format.json { render action: 'show', status: :created, location: #order_item }
else
format.html { redirect_to new_order_item_path, notice: 'We were unable to customize your trip.' }
format.json { render json: #order_item.errors, status: :unprocessable_entity }
end
end
end
rspec error message:
OrderItemsController POST create with invalid attributes re-renders the new method
Failure/Error: post :create, order_item: FactoryGirl.attributes_for(:order_item, :buyer_id => nil)
ActiveRecord::RecordInvalid:
Validation failed: Buyer can't be blank
# ./app/controllers/order_items_controller.rb:30:in `block in create'
# ./app/controllers/order_items_controller.rb:29:in `create'
# ./spec/controllers/order_items_controller_spec.rb:43:in `block (4 levels) in <top (required)>'
Thanks in advance.
Your test looks good; it's actually your code which is failing to work as you expect when the save fails. When you say "ActiveRecord actually tries to create that record which, due to validations, fails", that's exactly what you want your test to be doing, because you are trying to test what happens if the validation fails.
In your controller you are saving the record with save!. This will cause an error be raised if the save fails, which is why you immediately see a failure in rspec rather than it going on to the new view.
Instead you want to use save (without the bang). This will return true/false depending on the save success so you can use it in a condition.
Your controller code should be:
def create
#order_item = OrderItem.new(order_item_params)
respond_to do |format|
if #order_item.save ### ! removed
...
Don't use 'save!' ... you should be using 'save' which will return false if not valid.
Just to clarify: I'm new to Ruby and Rails.
I've tryed to solve my problem with the sugestions in here, here and here, but they didn't seem to have direct relation with my problem, or I'm too dumb do understand.
I'm trying to test a scenario where I don't update an object and I want my app to redirect. I'm not sure if my controller code is right, I think I'm probably not covering this scenario. Here's my test code:
test "should not update status if nothing has changed" do
sign_in users(:rodrigo)
put :update, id: #status
assert_redirected_to status_path(assigns(:status))
assert_equal assigns(:status).user_id, users(:rodrigo).id
end
, and my controller update code:
def update
#status = current_user.statuses.find(params[:id])
#document = #status.document
if params[:status] && params[:status].has_key?(:user_id)
params[:status].delete(:user_id)
end
respond_to do |format|
if #status.update_attributes(params[:status]) &&
#document && #document.update_attributes(params[:status][:document_attributes])
format.html { redirect_to #status, notice: 'Status was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
I've already tried to verify if #status.changed?, and it really didn't. I'm without options here. If anyone want to help and need more information, I can provide it.
Facepalm for me...
I've mentioned in my question:
I've already tried to verify if #status.changed?, and it really didn't.
It did change when I put something different in one of the model attributes, but I've only asked .changed? after saving my #status model. I'm really sorry about it, I'm yet just figuring out how Ruby on Rais works.
That said, I've came up with a solution to my problem, that was just setting the only one attribute of my model (except the id, of course) with the value from the params[:status] hash. And BEFORE saving it, I ask if #status.changed?. If it doesn't, I redirect_to the unchanged #status, otherwise, I just save it and go through the old code.
Of course that doesn't cover all my scenario, since I also have to check if my #document model has changed, but this is not the scope of this question.
When you generate a rails scaffold using a command like rails g scaffold Thing is there any way to avoid getting that annoying
respond_to do |format|
format.html # index.html.erb
format.json { render json: #things }
end
stuff in your controller?
I'm trying to teach a class on Rails and I'd like to start by having them generate a scaffold, but with all the json formatting it's much more complicated than it needs to be. I'd be much happier if they could generate a scaffold that created a controller like this:
class ThingsController < ApplicationController
def index
#things = Thing.all
end
def show
#thing = Thing.find(params[:id])
end
def new
#thing = Thing.new
end
def edit
#thing = Thing.find(params[:id])
end
def create
#thing = Thing.new(params[:thing])
if #thing.save
redirect_to #thing, notice: 'Thing was successfully created.'
else
render: "new"
end
end
end
def update
#thing = Thing.find(params[:id])
if #thing.update_attributes(params[:thing])
redirect_to #thing, notice: 'Thing was successfully updated.'
else
render: "edit"
end
end
end
def destroy
#thing = Thing.find(params[:id])
#thing.destroy
redirect_to things_url
end
end
Comment out gem jbuilder in your Gemfile and respond_to blocks won't be generated.
Just clone the file
https://github.com/rails/rails/blob/v5.2.2/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
to your
lib/rails/generators/rails/scaffold_controller/templates/controller.rb
path in your application and customize what you want. Also, you can write your own generators for scaffolding ( http://guides.rubyonrails.org/generators.html ).
I think you'd be missing an opportunity. For one thing, you'd be teaching non-standard Rails, so your students might be confused when they see the normal version in their own installations.
More importantly, the controllers are formatted that way for a reason. Rails puts an emphasis on REST, which encourages access to resources via multiple data formats. Many modern apps are de-emphasizing slower server-rendered html/erb responses in favor of json APIs. I realize this is a little over a year after your OP, and you have limited time in class, just adding some thoughts for anyone who might happen by. I think you could wave your hand over the respond_to and tell them it's setting you up for some future possibilities.
You'll notice that the JSON response is coded directly into the template for the rails generator here:
https://github.com/rails/rails/blob/master/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
I think something to note is that the scaffold generator is really intended to illustrate and moreover educate on how the Rails stack works, it shows how you can edit the controller to provide many different formats to suit your needs!
I'm trying to have the "show" action for my pages controller render a Liquid template instead of the normal view. The template itself is stored in the database.
This is my show action:
def show
#organization = Organization.find_by_subdomain(request.subdomain)
#template = Liquid::Template.parse(Template.find(#organization.current_template))
#page = #organization.pages.find(params[:id])
respond_to do |format|
format.html { render #template.render('page' => #page)}
format.json { render json: #page }
end
end
However, it raises this exception:
uninitialized constant PagesController::Liquid
I'm a RoR newbie, so I'm assuming what's happening is that it's trying to find the Liquid class in the PagesController class, instead of realizing it's a class unto itself. I'm following the (somewhat sparse) instructions here as best I can.
What am I doing wrong?
You need to include liquid in your Gemfile:
gem "liquid"
Then run bundle install and restart your rails server.