Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Image Upload with React Native, Expo ImagePicker, Rails, Axios and Paperclip

So far everything works in the backend regarding Rails and Paperclip. I have it set up so that when you create a new Post, the image within that post will be uploaded to AWS S3. It works fine on the backend. I am also using Expo's ImagePicker to grab an image from the users camera roll. However, when I'm trying to post something with Axios in React Native using formData in the front end, I'm getting this error:

Paperclip::AdapterRegistry::NoHandlerError - No handler found for 
"file:///Users/jimmy/Library/Developer/CoreSimulator/Devices/A3590E6A-
281B-4EFB-868C-9F5311718832/data/Containers/Data/Application/CB5ED945-
AA87-4E36-83B6-71426759C70C/Library/Caches/ExponentExperienceData/%2540anonymous%252Fartis
-ed15f4f4-b8d6-460f-a1b3-e06d546eda2a/ImagePicker/B3162237-9BCD-4721-
BDF2-D66BC047A6C0.jpg"

Here's some more snippets of my code:

React Native Submit handler in the PostForm:

onSubmit() {
    const { navigate } = this.props.navigation;
    return () => {
      const formData = new FormData();
      formData.append("post[title]", this.state.title);
      formData.append("post[body]", this.state.body);
      formData.append("post[user_id]", this.props.currentUser.id);
      formData.append("post[image]", this.state.image);
      this.props.createPost(formData).then((res) => {
        if (res.type) {
          navigate("Explore");
        }
      });
    };
  }

ImagePicker to get an image uri to display a preview as well as update the image uri in the parent component which is the PostForm:

_pickImage = async () => {
    let pickerResult = await ImagePicker.launchImageLibraryAsync({
      allowsEditing: true,
      aspect: [4, 3],
    });
    if (pickerResult.cancelled) {
      return;
    }
    this.setState({image: pickerResult.uri});
    this.props.updatePostWithImage(pickerResult.uri);
  };

Action and API Call:

export const createPost = (post) => dispatch => (
  postPost(post).then((res) => {
    return dispatch(receivePost(res.data));
  }).catch((errors) => {
  })
);

const url = "http://localhost:3000";

export const postPost = (post) => {
  return axios({
    method: 'POST',
    url: `${url}/api/posts`,
    dataType: "JSON",
    contentType: false,
    processData: false,
    data: post
  });
};

Post Controller:

def create
  @post = Post.new(post_params)
  if @post.save
    render :show
  else
    render json: @post.errors.full_messages, status: 422
  end
end

def post_params
  params.require(:post).permit(:title, :body, :image, :user_id)
end

Post Model:

class Post < ApplicationRecord
  validates :title, :body, presence: true

  belongs_to :user

  has_attached_file :image, default_url: "https://res.cloudinary.com/jun/image/upload/v1506659435/Doge_sggjpf.jpg"
  validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
end

Parameters that Rails receives with Axios POST request:

Parameters: {"post"=>{"title"=>"Test", "body"=>"Testing", "user_id"=>"1", "image"=>"file:///Users/jimmy/Library/Developer/CoreSimulator/Devices/A3590E6A-281B-4EFB-868C-9F5311718832/data/Containers/Data/Application/CB5ED945-AA87-4E36-83B6-71426759C70C/Library/Caches/ExponentExperienceData/%2540anonymous%252Fartis-ed15f4f4-b8d6-460f-a1b3-e06d546eda2a/ImagePicker/B3162237-9BCD-4721-BDF2-D66BC047A6C0.jpg"}}

I'm not really sure what's going on. The parameters looks fine to me, but I think it might be missing a lot of things that paperclip needs I would assume. But I'm not sure how to get them. I tried searching all over but couldn't find a solution that could help. I'm still fairly new to using some of these technologies, so please bear with me, haha.

If there is any other information I can add in to help debug this issue let me know. Thanks in advance!

like image 546
Jimmy Li Avatar asked Oct 14 '17 01:10

Jimmy Li


1 Answers

Welp, I found the issue and was able to fix it. I was missing additional information that Paperclip required on the back end. The only change I made was on the onSubmit handler function.

  onSubmit() {
    const { navigate } = this.props.navigation;
    return () => {
      let uriParts = this.state.image.split('.');
      let fileType = uriParts[uriParts.length - 1];
      console.log(fileType);
      const formData = new FormData();
      formData.append("post[title]", this.state.title);
      formData.append("post[body]", this.state.body);
      formData.append("post[user_id]", this.props.currentUser.id);
      formData.append("post[image]", {
        uri: this.state.image,
        name: `${this.state.title}.${fileType}`,
        type: `image/${fileType}`,
      });
      this.props.createPost(formData).then((res) => {
        if (res.type) {
          navigate("Explore");
        }
      });
    };
  }

Setting the uri, name and file type for the image fixed everything. I can now select an image from the camera roll and successfully create a post using that image, which gets uploaded to AWS S3 using paperclip. :D

like image 124
Jimmy Li Avatar answered Oct 12 '22 23:10

Jimmy Li