Rails beginner - How to make this API accept JSON? - ruby-on-rails

I am new to rails and am trying to connect my rails api for an article (consists of two fields - title and description) to an iOS application. I am trying to send JSON data in a POST request and then save that data in a database. I am wondering how to make my articles_controller accept and save json data.
Here is my code so far:
class ArticlesController < ApplicationController
before_action :set_article, only: [:edit, :update, :show, :destroy]
def index
#all_articles = Article.all
end
def new
#article = Article.new
end
def edit
end
def create
#article = Article.new(article_params)
if #article.save
flash[:notice] = "Article was sucessfully created"
redirect_to article_path(#article)
else
render 'new'
end
end
def show
end
def update
if #article.update(article_params)
flash[:notice] = "Article was successfully updated."
redirect_to article_path(#article)
else
render 'edit'
end
end
def destroy
#article.destroy
flash[:notice] = "Article was successfully deleted."
redirect_to(articles_path)
end
private
def set_article
#article = Article.find(params[:id])
end
def article_params
params.require(:article).permit(:title, :description)
end
end
The above code is able to submit a form on the webpage and save it to my database. I would like to alter it to accept json data from an iOS application and save to the database.
Thank you very much for any help

Make a route for POST method:
In config/routes.rb
match 'accept_post' => 'articles#accept_post', :via => :post
In Articles Controller
def accept_post
// get parameters as usual (like params[:title] etc.)
// do the saving to db
end
Important Note: Make the url publicly accessible. But do your own authentication, so others cannot POST to it.
You can use your existing action in controller (like create) if you want, just wanna give you an idea about it.
You may need to parse the JSON in controller:
require 'json'
JSON.parse(<json object>)
JSON.parse(response.body)

Related

Rails: can ActiveRecord method "destroy" go wrong and not be performed?

I am writing an app in RoR, and I was wondering if following if statement should be put there:
class ArticlesController < ApplicationController
before_action :set_user, only: %i[destroy edit]
...
def destroy
if #article.destroy
flash[:success] = 'Article deleted'
redirect_to articles_path
else
flash[:error] = 'Failed to delete the article'
redirect_to article_path(#article)
end
end
...
private
def set_user
#article = Article.find(params[:id])
if current_user.id == #article.author_id
#author = current_user
else
redirect_to article_path(#article), message: 'You can\'t do that'
end
end
end
Is it possible for "else" branch i destroy method to be called? I am writing specs for that controller and I can't possibly think of the way to test that code.
I used the same approach as with ".save", but there we are dealing with DB validation. If there is no way "else" can be called, I will just delete those lines.
I something goes wrong with searching for the article owner or finding the article by id, error is gonna be present earlier, in "set_user" method.

undefined method `user_name' for nil:NilClass

I'm trying to make a simple rails app, where useres can leave comments on posts.
When I make a new post, I run into a undefined method 'user_name' for nil:NilClass error.
Specifically, the following:
As you can see in the picture, #post.comments seems to contain a single comment with nil variables.
my comment controller is as follows:
before_action :set_post
def create
#comment = #post.comments.build(comment_params)
#comment.user_id = current_user.id
if #comment.save
flash[:success] = "You commented the hell out of that post!"
redirect_to #post
else
flash[:alert] = "Check the comment form, something went horribly wrong."
redicect_to #post
end
end
#...
private
def comment_params
params.require(:comment).permit(:content)
end
def set_post
#post = Post.find(params[:post_id])
end
And my post controller:
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :owned_post, only: [:edit, :update, :destroy]
#...
def create
#post = current_user.posts.build(post_params)
if #post.save
flash[:success] = "Your post has been created!"
redirect_to #post
else
flash.now[:alert] = "Your new post couldn't be created! Please check the form."
render :new
end
end
#...
private
def post_params
params.require(:post).permit(:image, :description)
end
def set_post
#post = Post.find(params[:id])
end
Thanks for the help. Sorry for and grammatical errors, I've been up for a while working on this, and am not a great speller when I'm awake.
try change
#comment.user_id = current_user.id
to
#comment.user = current_user
You need to either make sure comment does not get saved without an user/user_id, or you have to handle the case in view where user/user_id is nil
You are asking for the name of the user but you are not currently permitting a user_id in your comment_params:
This:
def comment_params
params.require(:comment).permit(:content)
end
Should be:
def comment_params
params.require(:comment).permit(:content, :user_id)
end
It is also possible that your code should be:
comment.user.name
instead of
comment.user.user_name
we would need to see your model to confirm. I would not use user_name as an attribute of user.
One of the comments for that post might not have a user. You can use try method here.
#comment.try(:user).try(:user_name)
But the ideal way to handle this would be to add a presence validation to the user model so that all comments created by any user in future will have a name.

Simple Form on Submit is not sending the input to MySQL

So as you all can see in the screen shot below in my blog form when I click submit when creating a new blog the parameters get sent but never actually get inserted into the MySQL command. Which you can see the post in the background is empty except for the Timestamp.
Now with that being said this same form is used for my Edit Blog page. My form is a partial rendered in the new blog page and the edit blog page. So if I go edit that same blog page that was created with no input up submit of the edit's the parameters actually go through and then the blog post will show will all the information from your edits.
class PostsController < ApplicationController
before_action :find_post, only: [:edit, :update, :show, :delete]
# Index action to render all posts
def index
#posts = Post.all
end
# New action for creating post
def new
#post = Post.new
end
# Create action saves the post into database
def create
#post = Post.new
if #post.save(post_params)
flash[:notice] = "Successfully created post!"
redirect_to post_path(#post)
else
flash[:alert] = "Error creating new post!"
render :new
end
end
# Edit action retrives the post and renders the edit page
def edit
end
# Update action updates the post with the new information
def update
if #post.update_attributes(post_params)
flash[:notice] = "Successfully updated post!"
redirect_to post_path(#post)
else
flash[:alert] = "Error updating post!"
render :edit
end
end
# The show action renders the individual post after retrieving the id
def show
end
# The destroy action removes the post permanently from the database
def destroy
if #post.destroy
flash[:notice] = "Successfully deleted post!"
redirect_to posts_path
else
flash[:alert] = "Error updating post!"
end
end
private
def post_params
params.require(:post).permit(:strain, :straintype, :style, :light, :temp, :breeder, :private, :notes, :nutrients)
end
def find_post
#post = Post.find(params[:id])
end
end
I just don't understand why the edit saves correctly but no the initial submit.
I think maybe it should be .create(post_params) instead of .new
http://guides.rubyonrails.org/active_record_basics.html#create
Rails: Difference between create and new methods in ActiveRecord?

Route redirecting issue with devise and rails

I have a has_one association in my model with my user. What I'm trying to do here is simple but I'm having a hard time understanding whats wrong here. So since I have a has_one association with my model, in my mind I was simply thinking that if the user has already created the model associated with the has_one association if he tries accessing "localhost3000/model/new" I would redirect him to the edit page of this particular model. Here is what I have but its telling me its not working as intended. It's as if my if statement is not catching anything
class BusinessesController < ApplicationController
before_action :set_business, only: [:show, :edit, :update, :destroy]
def index
#businesses = Business.all
#buzzs = Buzz.all
end
def show
end
def new
if current_user.business.nil?
#business = current_user.build_business
else
render 'edit'
end
end
def edit
end
def create
#business = current_user.build_business(business_params)
if #business.save
redirect_to #business, notice: 'Business was successfully created.'
else
render "new"
end
end
This error does not make a lot of sense to me because it says its an error in the "new" controller which would have rendered it to the edit path thus not being nil
This is happening because you're not setting #business when redirecting to 'edit'. Try this:
def new
if current_user.business.nil?
#business = current_user.build_business
else
#business = current_user.business
render 'edit'
end
end

Issue with before_filter

Please help me try and understand what is happening here:
I need to approve a nested snippet but when I do it says it cannot find book. I think it may be an issue with the routes because the URL in the browser doesn't match the rake routes.
If someone could hold my hand and explain this as you would to a child :)
Couldn't find Book without an ID
Below is the controller with snippets#approve and the before_filter.
class SnippetsController < ApplicationController
before_filter :authenticate_user!
before_filter :find_book
def create
#raise params.inspect
#snippet = #book.snippets.create(params[:snippet])
#snippet.user = current_user
if #snippet.save
redirect_to #book
flash[:success] = "Snippet submitted and awaiting approval."
else
flash[:base] = "Someone else has submitted a snippet, please try again later"
redirect_to #book
end
end
def approve
#raise params.inspect
#snippet = #book.snippets.find(params[:id])
#snippet.update_attribute(:approved, true)
redirect_to admins_path
end
def edit
#snippet = #book.snippets.find(params[:id])
end
def update
#snippet = #book.snippets.find(params[:id])
respond_to do |format|
if #snippet.update_attributes(params[:snippet])
format.html { redirect_to #book, notice: 'Comment was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
private
def find_book
#raise params.inspect
#book = Book.find(params[:book_id])
end
end
Now I understand that since I'm doing a post my rake routes says this.
/books/:book_id/snippets/:id(.:format)
Here is the routes for the custom route:
active_snippet POST /snippets/:id/activate(.:format)
This is my custom routes for book && snippet :approval
post "books/:id/activate" => "books#approve", :as => "active_book"
post "snippets/:id/activate" => "snippets#approve", :as => "active_snippet"
I've currently got this in my browser ../snippets/2/activate
Erm.... Not sure if I'm thinking correctly.
You're sending a POST request to snippets/:id/activate which calls snippets#approve.
There is a before_filter on the entire SnippetsController that calls find_book which executes #book = Book.find(params[:book_id]). Because your path is snippets/:id/activate, params[:book_id] is nil and hence you are getting that error.
You need to either change your snippets#approve path to include the book_id, or pass the book_id as a POST param so that your before filter has access to it.

Resources